feat(triple): Dubbo triple&rest protocol convergense (#13607)
This commit is contained in:
parent
e60f24cb7f
commit
2dde7ac09e
|
|
@ -120,3 +120,7 @@ dubbo-tracing
|
|||
dubbo-xds
|
||||
dubbo-plugin-proxy-bytebuddy
|
||||
dubbo-plugin-loom
|
||||
dubbo-rest-jaxrs
|
||||
dubbo-rest-servlet
|
||||
dubbo-rest-spring
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@
|
|||
*/
|
||||
package org.apache.dubbo.common.extension;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Uniform accessor for extension
|
||||
*/
|
||||
|
|
@ -24,7 +27,7 @@ public interface ExtensionAccessor {
|
|||
ExtensionDirector getExtensionDirector();
|
||||
|
||||
default <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
|
||||
return this.getExtensionDirector().getExtensionLoader(type);
|
||||
return getExtensionDirector().getExtensionLoader(type);
|
||||
}
|
||||
|
||||
default <T> T getExtension(Class<T> type, String name) {
|
||||
|
|
@ -41,4 +44,21 @@ public interface ExtensionAccessor {
|
|||
ExtensionLoader<T> extensionLoader = getExtensionLoader(type);
|
||||
return extensionLoader != null ? extensionLoader.getDefaultExtension() : null;
|
||||
}
|
||||
|
||||
default <T> List<T> getActivateExtensions(Class<T> type) {
|
||||
ExtensionLoader<T> extensionLoader = getExtensionLoader(type);
|
||||
return extensionLoader != null ? extensionLoader.getActivateExtensions() : Collections.emptyList();
|
||||
}
|
||||
|
||||
default <T> T getFirstActivateExtension(Class<T> type) {
|
||||
ExtensionLoader<T> extensionLoader = getExtensionLoader(type);
|
||||
if (extensionLoader == null) {
|
||||
throw new IllegalArgumentException("ExtensionLoader for [" + type + "] is not found");
|
||||
}
|
||||
List<T> extensions = extensionLoader.getActivateExtensions();
|
||||
if (extensions.isEmpty()) {
|
||||
throw new IllegalArgumentException("No activate extensions for [" + type + "] found");
|
||||
}
|
||||
return extensions.get(0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,13 @@
|
|||
*/
|
||||
package org.apache.dubbo.common.io;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Stream utils.
|
||||
|
|
@ -229,4 +234,51 @@ public class StreamUtils {
|
|||
is.skip(is.available());
|
||||
}
|
||||
}
|
||||
|
||||
public static void copy(InputStream in, OutputStream out) throws IOException {
|
||||
if (in.getClass() == ByteArrayInputStream.class) {
|
||||
copy((ByteArrayInputStream) in, out);
|
||||
return;
|
||||
}
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
public static void copy(ByteArrayInputStream in, OutputStream out) throws IOException {
|
||||
int len = in.available();
|
||||
byte[] buffer = new byte[len];
|
||||
in.read(buffer, 0, len);
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
|
||||
public static byte[] readBytes(InputStream in) throws IOException {
|
||||
if (in.getClass() == ByteArrayInputStream.class) {
|
||||
return readBytes((ByteArrayInputStream) in);
|
||||
}
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, bytesRead);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] readBytes(ByteArrayInputStream in) throws IOException {
|
||||
int len = in.available();
|
||||
byte[] bytes = new byte[len];
|
||||
in.read(bytes, 0, len);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static String toString(InputStream in) throws IOException {
|
||||
return new String(readBytes(in), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static String toString(InputStream in, Charset charset) throws IOException {
|
||||
return new String(readBytes(in), charset);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ public interface JsonUtil {
|
|||
|
||||
Map<String, ?> getObject(Map<String, ?> obj, String key);
|
||||
|
||||
Object convertObject(Object obj, Type type);
|
||||
|
||||
Object convertObject(Object obj, Class<?> clazz);
|
||||
|
||||
Double getNumberAsDouble(Map<String, ?> obj, String key);
|
||||
|
||||
Integer getNumberAsInteger(Map<String, ?> obj, String key);
|
||||
|
|
|
|||
|
|
@ -36,4 +36,14 @@ public class FastJson2Impl extends AbstractJsonUtilImpl {
|
|||
public String toJson(Object obj) {
|
||||
return com.alibaba.fastjson2.JSON.toJSONString(obj, JSONWriter.Feature.WriteEnumsUsingName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convertObject(Object obj, Type type) {
|
||||
return com.alibaba.fastjson2.util.TypeUtils.cast(obj, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convertObject(Object obj, Class<?> clazz) {
|
||||
return com.alibaba.fastjson2.util.TypeUtils.cast(obj, clazz);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.dubbo.common.json.impl;
|
|||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
|
||||
public class FastJsonImpl extends AbstractJsonUtilImpl {
|
||||
|
|
@ -37,4 +38,14 @@ public class FastJsonImpl extends AbstractJsonUtilImpl {
|
|||
public String toJson(Object obj) {
|
||||
return com.alibaba.fastjson.JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convertObject(Object obj, Type type) {
|
||||
return com.alibaba.fastjson.util.TypeUtils.cast(obj, type, ParserConfig.getGlobalInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convertObject(Object obj, Class<?> clazz) {
|
||||
return com.alibaba.fastjson.util.TypeUtils.cast(obj, clazz, ParserConfig.getGlobalInstance());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,18 @@ public class GsonImpl extends AbstractJsonUtilImpl {
|
|||
return getGson().toJson(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convertObject(Object obj, Type type) {
|
||||
Gson gson = getGson();
|
||||
return gson.fromJson(gson.toJsonTree(obj), type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convertObject(Object obj, Class<?> clazz) {
|
||||
Gson gson = getGson();
|
||||
return gson.fromJson(gson.toJsonTree(obj), clazz);
|
||||
}
|
||||
|
||||
private Gson getGson() {
|
||||
if (gsonCache == null || !(gsonCache instanceof Gson)) {
|
||||
synchronized (this) {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,17 @@ public class JacksonImpl extends AbstractJsonUtilImpl {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convertObject(Object obj, Type type) {
|
||||
JsonMapper mapper = getJackson();
|
||||
return mapper.convertValue(obj, mapper.constructType(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convertObject(Object obj, Class<?> clazz) {
|
||||
return getJackson().convertValue(obj, clazz);
|
||||
}
|
||||
|
||||
private JsonMapper getJackson() {
|
||||
if (jacksonCache == null || !(jacksonCache instanceof JsonMapper)) {
|
||||
synchronized (this) {
|
||||
|
|
|
|||
|
|
@ -76,4 +76,8 @@ public final class ArrayUtils {
|
|||
public static <T> T[] of(T... values) {
|
||||
return values;
|
||||
}
|
||||
|
||||
public static <T> T first(T[] data) {
|
||||
return isEmpty(data) ? null : data[0];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,12 @@ public abstract class Assert {
|
|||
}
|
||||
}
|
||||
|
||||
public static void notNull(Object obj, String format, Object... args) {
|
||||
if (obj == null) {
|
||||
throw new IllegalArgumentException(String.format(format, args));
|
||||
}
|
||||
}
|
||||
|
||||
public static void notEmptyString(String str, String message) {
|
||||
if (StringUtils.isEmpty(str)) {
|
||||
throw new IllegalArgumentException(message);
|
||||
|
|
|
|||
|
|
@ -327,6 +327,10 @@ public class ClassUtils {
|
|||
return type != null && (type.isPrimitive() || isSimpleType(type));
|
||||
}
|
||||
|
||||
public static boolean isPrimitiveWrapper(Class<?> type) {
|
||||
return PRIMITIVE_WRAPPER_TYPE_MAP.containsKey(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* The specified type is simple type or not
|
||||
*
|
||||
|
|
|
|||
|
|
@ -24,11 +24,14 @@ import java.util.Collections;
|
|||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Collections.emptySet;
|
||||
|
|
@ -404,13 +407,19 @@ public class CollectionUtils {
|
|||
return null;
|
||||
}
|
||||
if (values instanceof List) {
|
||||
List<T> list = (List<T>) values;
|
||||
return list.get(0);
|
||||
return ((List<T>) values).get(0);
|
||||
} else {
|
||||
return values.iterator().next();
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T first(List<T> values) {
|
||||
if (isEmpty(values)) {
|
||||
return null;
|
||||
}
|
||||
return values.get(0);
|
||||
}
|
||||
|
||||
public static <T> Set<T> toTreeSet(Set<T> set) {
|
||||
if (isEmpty(set)) {
|
||||
return set;
|
||||
|
|
@ -420,4 +429,78 @@ public class CollectionUtils {
|
|||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
public static <T> Set<T> newHashSet(int expectedSize) {
|
||||
return new HashSet<>(capacity(expectedSize));
|
||||
}
|
||||
|
||||
public static <T> Set<T> newLinkedHashSet(int expectedSize) {
|
||||
return new LinkedHashSet<>(capacity(expectedSize));
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> newHashMap(int expectedSize) {
|
||||
return new HashMap<>(capacity(expectedSize));
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> newLinkedHashMap(int expectedSize) {
|
||||
return new LinkedHashMap<>(capacity(expectedSize));
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> newConcurrentHashMap(int expectedSize) {
|
||||
if (JRE.JAVA_8.isCurrentVersion()) {
|
||||
return new SafeConcurrentHashMap<>(capacity(expectedSize));
|
||||
}
|
||||
return new ConcurrentHashMap<>(capacity(expectedSize));
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> newConcurrentHashMap() {
|
||||
if (JRE.JAVA_8.isCurrentVersion()) {
|
||||
return new SafeConcurrentHashMap<>();
|
||||
}
|
||||
return new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public static int capacity(int expectedSize) {
|
||||
if (expectedSize < 3) {
|
||||
if (expectedSize < 0) {
|
||||
throw new IllegalArgumentException("expectedSize cannot be negative but was: " + expectedSize);
|
||||
}
|
||||
return expectedSize + 1;
|
||||
}
|
||||
if (expectedSize < 1 << (Integer.SIZE - 2)) {
|
||||
return (int) (expectedSize / 0.75F + 1.0F);
|
||||
}
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public static class SafeConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SafeConcurrentHashMap() {}
|
||||
|
||||
public SafeConcurrentHashMap(int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
}
|
||||
|
||||
public SafeConcurrentHashMap(Map<? extends K, ? extends V> m) {
|
||||
super(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
|
||||
V value = get(key);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
value = mappingFunction.apply(key);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
V exists = putIfAbsent(key, value);
|
||||
if (exists != null) {
|
||||
return exists;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.common.utils;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public final class DateUtils {
|
||||
|
||||
public static final ZoneId GMT = ZoneId.of("GMT");
|
||||
public static final ZoneId UTC = ZoneId.of("UTC");
|
||||
|
||||
public static final String DATE = "yyyy-MM-dd";
|
||||
public static final String DATE_MIN = "yyyy-MM-dd HH:mm";
|
||||
public static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";
|
||||
public static final String JDK_TIME = "EEE MMM dd HH:mm:ss zzz yyyy";
|
||||
public static final String ASC_TIME = "EEE MMM d HH:mm:ss yyyy";
|
||||
public static final String RFC1036 = "EEE, dd-MMM-yy HH:mm:ss zzz";
|
||||
|
||||
public static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern(DATE);
|
||||
public static final DateTimeFormatter DATE_MIN_FORMAT = DateTimeFormatter.ofPattern(DATE_MIN);
|
||||
public static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern(DATE_TIME);
|
||||
public static final DateTimeFormatter JDK_TIME_FORMAT = DateTimeFormatter.ofPattern(JDK_TIME, Locale.US);
|
||||
public static final DateTimeFormatter ASC_TIME_FORMAT = DateTimeFormatter.ofPattern(ASC_TIME, Locale.US);
|
||||
public static final DateTimeFormatter RFC1036_FORMAT = DateTimeFormatter.ofPattern(RFC1036, Locale.US);
|
||||
|
||||
private static final Map<String, DateTimeFormatter> CACHE = new LRUCache<>(64);
|
||||
private static final List<DateTimeFormatter> CUSTOM_FORMATTERS = new CopyOnWriteArrayList<>();
|
||||
|
||||
private DateUtils() {}
|
||||
|
||||
public static void registerFormatter(String pattern) {
|
||||
CUSTOM_FORMATTERS.add(DateTimeFormatter.ofPattern(pattern));
|
||||
}
|
||||
|
||||
public static void registerFormatter(DateTimeFormatter formatter) {
|
||||
CUSTOM_FORMATTERS.add(formatter);
|
||||
}
|
||||
|
||||
public static Date parse(String str, String pattern) {
|
||||
if (DATE_TIME.equals(pattern)) {
|
||||
return parse(str, DATE_TIME_FORMAT);
|
||||
}
|
||||
DateTimeFormatter formatter = getFormatter(pattern);
|
||||
return parse(str, formatter);
|
||||
}
|
||||
|
||||
public static Date parse(String str, DateTimeFormatter formatter) {
|
||||
return toDate(formatter.parse(str));
|
||||
}
|
||||
|
||||
public static String format(Date date) {
|
||||
return format(date, DATE_TIME_FORMAT);
|
||||
}
|
||||
|
||||
public static String format(Date date, String pattern) {
|
||||
if (DATE_TIME.equals(pattern)) {
|
||||
return format(date, DATE_TIME_FORMAT);
|
||||
}
|
||||
DateTimeFormatter formatter = getFormatter(pattern);
|
||||
return format(date, formatter);
|
||||
}
|
||||
|
||||
public static String format(Date date, DateTimeFormatter formatter) {
|
||||
return formatter.format(ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()));
|
||||
}
|
||||
|
||||
public static String format(Date date, DateTimeFormatter formatter, ZoneId zone) {
|
||||
return formatter.format(ZonedDateTime.ofInstant(date.toInstant(), zone));
|
||||
}
|
||||
|
||||
public static String formatGMT(Date date, DateTimeFormatter formatter) {
|
||||
return formatter.format(ZonedDateTime.ofInstant(date.toInstant(), GMT));
|
||||
}
|
||||
|
||||
public static String formatUTC(Date date, DateTimeFormatter formatter) {
|
||||
return formatter.format(ZonedDateTime.ofInstant(date.toInstant(), UTC));
|
||||
}
|
||||
|
||||
public static String formatHeader(Date date) {
|
||||
return DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.ofInstant(date.toInstant(), GMT));
|
||||
}
|
||||
|
||||
private static DateTimeFormatter getFormatter(String pattern) {
|
||||
return CACHE.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
|
||||
}
|
||||
|
||||
public static Date parse(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Date) {
|
||||
return (Date) value;
|
||||
}
|
||||
if (value instanceof Calendar) {
|
||||
return ((Calendar) value).getTime();
|
||||
}
|
||||
if (value.getClass() == Instant.class) {
|
||||
return Date.from((Instant) value);
|
||||
}
|
||||
if (value instanceof TemporalAccessor) {
|
||||
return Date.from(Instant.from((TemporalAccessor) value));
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return new Date(((Number) value).longValue());
|
||||
}
|
||||
if (value instanceof CharSequence) {
|
||||
return parse(value.toString());
|
||||
}
|
||||
throw new IllegalArgumentException("Can not cast to Date, value : '" + value + "'");
|
||||
}
|
||||
|
||||
public static Date parse(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String str = value.trim();
|
||||
int len = str.length();
|
||||
if (len == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean isIso = true;
|
||||
boolean isNumeric = true;
|
||||
boolean hasDate = false;
|
||||
boolean hasTime = false;
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = str.charAt(i);
|
||||
switch (c) {
|
||||
case ' ':
|
||||
isIso = false;
|
||||
break;
|
||||
case '-':
|
||||
hasDate = true;
|
||||
break;
|
||||
case 'T':
|
||||
case ':':
|
||||
hasTime = true;
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
continue;
|
||||
default:
|
||||
}
|
||||
if (isNumeric) {
|
||||
isNumeric = false;
|
||||
}
|
||||
}
|
||||
DateTimeFormatter formatter = null;
|
||||
if (isIso) {
|
||||
if (hasDate) {
|
||||
formatter = hasTime ? DateTimeFormatter.ISO_DATE_TIME : DateTimeFormatter.ISO_DATE;
|
||||
} else if (hasTime) {
|
||||
formatter = DateTimeFormatter.ISO_TIME;
|
||||
}
|
||||
}
|
||||
if (isNumeric) {
|
||||
long num = Long.parseLong(str);
|
||||
if (num > 21000101 || num < 19700101) {
|
||||
return new Date(num);
|
||||
}
|
||||
formatter = DateTimeFormatter.BASIC_ISO_DATE;
|
||||
}
|
||||
switch (len) {
|
||||
case 10:
|
||||
formatter = DATE_FORMAT;
|
||||
break;
|
||||
case 16:
|
||||
formatter = DATE_MIN_FORMAT;
|
||||
break;
|
||||
case 19:
|
||||
formatter = DATE_TIME_FORMAT;
|
||||
break;
|
||||
case 23:
|
||||
case 24:
|
||||
formatter = ASC_TIME_FORMAT;
|
||||
break;
|
||||
case 27:
|
||||
formatter = RFC1036_FORMAT;
|
||||
break;
|
||||
case 28:
|
||||
formatter = JDK_TIME_FORMAT;
|
||||
break;
|
||||
case 29:
|
||||
formatter = DateTimeFormatter.RFC_1123_DATE_TIME;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
if (formatter != null) {
|
||||
try {
|
||||
return toDate(formatter.parse(str));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
for (DateTimeFormatter dtf : CUSTOM_FORMATTERS) {
|
||||
try {
|
||||
return parse(str, dtf);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Can not cast to Date, value : '" + value + "'");
|
||||
}
|
||||
|
||||
public static Date toDate(TemporalAccessor temporal) {
|
||||
if (temporal instanceof Instant) {
|
||||
return Date.from((Instant) temporal);
|
||||
}
|
||||
long timestamp;
|
||||
if (temporal.isSupported(ChronoField.EPOCH_DAY)) {
|
||||
timestamp = temporal.getLong(ChronoField.EPOCH_DAY) * 86400000;
|
||||
} else {
|
||||
timestamp = LocalDate.now().toEpochDay() * 86400000;
|
||||
}
|
||||
if (temporal.isSupported(ChronoField.MILLI_OF_DAY)) {
|
||||
timestamp += temporal.getLong(ChronoField.MILLI_OF_DAY);
|
||||
}
|
||||
if (temporal.isSupported(ChronoField.OFFSET_SECONDS)) {
|
||||
timestamp -= temporal.getLong(ChronoField.OFFSET_SECONDS) * 1000;
|
||||
} else {
|
||||
timestamp -= TimeZone.getDefault().getRawOffset();
|
||||
}
|
||||
return new Date(timestamp);
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +53,7 @@ public class JsonUtils {
|
|||
case "jackson":
|
||||
instance = new JacksonImpl();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
if (instance != null && instance.isSupport()) {
|
||||
jsonUtil = instance;
|
||||
|
|
@ -123,6 +124,14 @@ public class JsonUtils {
|
|||
return getJson().getObject(obj, key);
|
||||
}
|
||||
|
||||
public static Object convertObject(Object obj, Type targetType) {
|
||||
return getJson().convertObject(obj, targetType);
|
||||
}
|
||||
|
||||
public static Object convertObject(Object obj, Class<?> targetType) {
|
||||
return getJson().convertObject(obj, targetType);
|
||||
}
|
||||
|
||||
public static Double getNumberAsDouble(Map<String, ?> obj, String key) {
|
||||
return getJson().getNumberAsDouble(obj, key);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,13 +19,14 @@ package org.apache.dubbo.common.utils;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* LRU-2
|
||||
* </p>
|
||||
* <p>
|
||||
* When the data accessed for the first time, add it to history list. If the size of history list reaches max capacity, eliminate the earliest data (first in first out).
|
||||
* When the data already exists in the history list, and be accessed for the second time, then it will be put into cache.
|
||||
*
|
||||
* </p>
|
||||
* TODO, consider replacing with ConcurrentHashMap to improve performance under concurrency
|
||||
*/
|
||||
public class LRU2Cache<K, V> extends LinkedHashMap<K, V> {
|
||||
|
|
@ -33,8 +34,8 @@ public class LRU2Cache<K, V> extends LinkedHashMap<K, V> {
|
|||
private static final long serialVersionUID = -5167631809472116969L;
|
||||
|
||||
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
|
||||
|
||||
private static final int DEFAULT_MAX_CAPACITY = 1000;
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private volatile int maxCapacity;
|
||||
|
||||
|
|
@ -94,6 +95,16 @@ public class LRU2Cache<K, V> extends LinkedHashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V computeIfAbsent(K key, Function<? super K, ? extends V> fn) {
|
||||
V value = get(key);
|
||||
if (value == null) {
|
||||
value = fn.apply(key);
|
||||
put(key, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
lock.lock();
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.dubbo.common.utils;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A 'least recently used' cache based on LinkedHashMap.
|
||||
|
|
@ -31,8 +32,8 @@ public class LRUCache<K, V> extends LinkedHashMap<K, V> {
|
|||
private static final long serialVersionUID = -5167631809472116969L;
|
||||
|
||||
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
|
||||
|
||||
private static final int DEFAULT_MAX_CAPACITY = 1000;
|
||||
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private volatile int maxCapacity;
|
||||
|
||||
|
|
@ -110,6 +111,20 @@ public class LRUCache<K, V> extends LinkedHashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V computeIfAbsent(K key, Function<? super K, ? extends V> fn) {
|
||||
V value = get(key);
|
||||
if (value == null) {
|
||||
lock.lock();
|
||||
try {
|
||||
return super.computeIfAbsent(key, fn);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public void lock() {
|
||||
lock.lock();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.common.utils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class Pair<L, R> implements Map.Entry<L, R>, Comparable<Pair<L, R>>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static final Pair NULL = new Pair<>(null, null);
|
||||
|
||||
public final L left;
|
||||
public final R right;
|
||||
|
||||
public static <L, R> Pair<L, R> of(L left, R right) {
|
||||
return left == null && right == null ? nullPair() : new Pair<>(left, right);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <L, R> Pair<L, R> nullPair() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <L, R> Map<L, R> toMap(Pair<L, R>... pairs) {
|
||||
if (pairs == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return toMap(Arrays.asList(pairs));
|
||||
}
|
||||
|
||||
public static <L, R> Map<L, R> toMap(Collection<Pair<L, R>> pairs) {
|
||||
if (pairs == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<L, R> map = CollectionUtils.newLinkedHashMap(pairs.size());
|
||||
for (Pair<L, R> pair : pairs) {
|
||||
map.put(pair.getLeft(), pair.getRight());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <L, R> List<Pair<L, R>> toPairs(Map<L, R> map) {
|
||||
if (map == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Pair<L, R>> pairs = new ArrayList<>(map.size());
|
||||
for (Map.Entry<L, R> entry : map.entrySet()) {
|
||||
pairs.add(of(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
public Pair(L left, R right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public L getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public R getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
return this == NULL || left == null && right == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public L getKey() {
|
||||
return left;
|
||||
}
|
||||
|
||||
@Override
|
||||
public R getValue() {
|
||||
return right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public R setValue(R value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public int compareTo(Pair<L, R> other) {
|
||||
return left.equals(other.left)
|
||||
? ((Comparable<R>) right).compareTo(other.right)
|
||||
: ((Comparable<L>) left).compareTo(other.left);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(left) ^ Objects.hashCode(right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (other instanceof Map.Entry) {
|
||||
Map.Entry<?, ?> that = (Map.Entry<?, ?>) other;
|
||||
return Objects.equals(left, that.getKey()) && Objects.equals(right, that.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + left + ", " + right + ')';
|
||||
}
|
||||
}
|
||||
|
|
@ -1256,10 +1256,6 @@ public final class StringUtils {
|
|||
|
||||
/**
|
||||
* Test str whether starts with the prefix ignore case.
|
||||
*
|
||||
* @param str
|
||||
* @param prefix
|
||||
* @return
|
||||
*/
|
||||
public static boolean startsWithIgnoreCase(String str, String prefix) {
|
||||
if (str == null || prefix == null || str.length() < prefix.length()) {
|
||||
|
|
@ -1268,4 +1264,102 @@ public final class StringUtils {
|
|||
// return str.substring(0, prefix.length()).equalsIgnoreCase(prefix);
|
||||
return str.regionMatches(true, 0, prefix, 0, prefix.length());
|
||||
}
|
||||
|
||||
public static String defaultIf(String str, String defaultStr) {
|
||||
return isEmpty(str) ? defaultStr : str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a substring from 'str' between 'start' and 'end', or to the end if 'end' is -1
|
||||
*/
|
||||
public static String substring(String str, int start, int end) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
return end == INDEX_NOT_FOUND ? str.substring(start) : str.substring(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a substring from the given string that precedes the first occurrence of the specified character separator.
|
||||
* If the character is not found, the entire string is returned.
|
||||
*/
|
||||
public static String substringBefore(String str, int separator) {
|
||||
if (isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
int index = str.indexOf(separator);
|
||||
return index == INDEX_NOT_FOUND ? str : str.substring(0, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a substring from the given string that precedes the first occurrence of the specified string separator.
|
||||
* If the separator is not found or is null, the entire string is returned.
|
||||
*/
|
||||
public static String substringBefore(String str, String separator) {
|
||||
if (isEmpty(str) || separator == null) {
|
||||
return str;
|
||||
}
|
||||
if (separator.isEmpty()) {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
int index = str.indexOf(separator);
|
||||
return index == INDEX_NOT_FOUND ? str : str.substring(0, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenize the given String into a String array.
|
||||
* Trims tokens and omits empty tokens.
|
||||
*/
|
||||
public static String[] tokenize(String str, char... separators) {
|
||||
if (isEmpty(str)) {
|
||||
return EMPTY_STRING_ARRAY;
|
||||
}
|
||||
return tokenizeToList(str, separators).toArray(EMPTY_STRING_ARRAY);
|
||||
}
|
||||
|
||||
public static List<String> tokenizeToList(String str, char... separators) {
|
||||
if (isEmpty(str)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (separators == null || separators.length == 0) {
|
||||
separators = new char[] {','};
|
||||
}
|
||||
List<String> tokens = new ArrayList<>();
|
||||
int start = -1, end = 0;
|
||||
int i = 0;
|
||||
out:
|
||||
for (int len = str.length(), sLen = separators.length; i < len; i++) {
|
||||
char c = str.charAt(i);
|
||||
for (int j = 0; j < sLen; j++) {
|
||||
if (c == separators[j]) {
|
||||
if (start > -1) {
|
||||
tokens.add(str.substring(start, end + 1));
|
||||
start = -1;
|
||||
}
|
||||
continue out;
|
||||
}
|
||||
}
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
break;
|
||||
default:
|
||||
if (start == -1) {
|
||||
start = i;
|
||||
}
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (start > -1) {
|
||||
String part = str.substring(start, end + 1);
|
||||
if (tokens.isEmpty()) {
|
||||
return Collections.singletonList(part);
|
||||
}
|
||||
tokens.add(part);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Configuration for triple rest protocol.
|
||||
*/
|
||||
public class RestConfig implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Maximum allowed size for request bodies.
|
||||
* Limits the size of request to prevent excessively large request.
|
||||
* <p>The default value is 8MiB.
|
||||
*/
|
||||
private Integer maxBodySize;
|
||||
|
||||
/**
|
||||
* Maximum allowed size for response bodies.
|
||||
* Limits the size of responses to prevent excessively large response.
|
||||
* <p>The default value is 8MiB.
|
||||
*/
|
||||
private Integer maxResponseBodySize;
|
||||
|
||||
/**
|
||||
* Whether path matching should be match paths with a trailing slash.
|
||||
* If enabled, a method mapped to "/users" also matches to "/users/".
|
||||
* <p>The default value is {@code true}.
|
||||
*/
|
||||
private Boolean trailingSlashMatch;
|
||||
|
||||
/**
|
||||
* Whether path matching should be case-sensitive.
|
||||
* If enabled, a method mapped to "/users" won't match to "/Users/".
|
||||
* <p>The default value is {@code false}.
|
||||
*/
|
||||
private Boolean caseSensitiveMatch;
|
||||
|
||||
/**
|
||||
* Whether path matching uses suffix pattern matching (".*").
|
||||
* If enabled, a method mapped to "/users" also matches to "/users.*".
|
||||
* <p>This also enables suffix content negotiation, with the media-type
|
||||
* inferred from the URL suffix, e.g., ".json" for "application/json".
|
||||
* <p>The default value is {@code true}.
|
||||
*/
|
||||
private Boolean suffixPatternMatch;
|
||||
|
||||
/**
|
||||
* The parameter name that can be used to specify the response format.
|
||||
* <p>The default value is 'format'.
|
||||
*/
|
||||
private String formatParameterName;
|
||||
|
||||
public Integer getMaxBodySize() {
|
||||
return maxBodySize;
|
||||
}
|
||||
|
||||
public void setMaxBodySize(Integer maxBodySize) {
|
||||
this.maxBodySize = maxBodySize;
|
||||
}
|
||||
|
||||
public Integer getMaxResponseBodySize() {
|
||||
return maxResponseBodySize;
|
||||
}
|
||||
|
||||
public void setMaxResponseBodySize(Integer maxResponseBodySize) {
|
||||
this.maxResponseBodySize = maxResponseBodySize;
|
||||
}
|
||||
|
||||
public Boolean getTrailingSlashMatch() {
|
||||
return trailingSlashMatch;
|
||||
}
|
||||
|
||||
public void setTrailingSlashMatch(Boolean trailingSlashMatch) {
|
||||
this.trailingSlashMatch = trailingSlashMatch;
|
||||
}
|
||||
|
||||
public Boolean getCaseSensitiveMatch() {
|
||||
return caseSensitiveMatch;
|
||||
}
|
||||
|
||||
public void setCaseSensitiveMatch(Boolean caseSensitiveMatch) {
|
||||
this.caseSensitiveMatch = caseSensitiveMatch;
|
||||
}
|
||||
|
||||
public Boolean getSuffixPatternMatch() {
|
||||
return suffixPatternMatch;
|
||||
}
|
||||
|
||||
public void setSuffixPatternMatch(Boolean suffixPatternMatch) {
|
||||
this.suffixPatternMatch = suffixPatternMatch;
|
||||
}
|
||||
|
||||
public String getFormatParameterName() {
|
||||
return formatParameterName;
|
||||
}
|
||||
|
||||
public void setFormatParameterName(String formatParameterName) {
|
||||
this.formatParameterName = formatParameterName;
|
||||
}
|
||||
}
|
||||
|
|
@ -55,6 +55,11 @@ public class TripleConfig implements Serializable {
|
|||
*/
|
||||
private String maxHeaderListSize;
|
||||
|
||||
/**
|
||||
* Whether to pass through standard HTTP headers, default is false.
|
||||
*/
|
||||
private Boolean passThroughStandardHttpHeaders;
|
||||
|
||||
public String getHeaderTableSize() {
|
||||
return headerTableSize;
|
||||
}
|
||||
|
|
@ -102,4 +107,12 @@ public class TripleConfig implements Serializable {
|
|||
public void setMaxHeaderListSize(String maxHeaderListSize) {
|
||||
this.maxHeaderListSize = maxHeaderListSize;
|
||||
}
|
||||
|
||||
public Boolean getPassThroughStandardHttpHeaders() {
|
||||
return passThroughStandardHttpHeaders;
|
||||
}
|
||||
|
||||
public void setPassThroughStandardHttpHeaders(Boolean passThroughStandardHttpHeaders) {
|
||||
this.passThroughStandardHttpHeaders = passThroughStandardHttpHeaders;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1218,6 +1218,7 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
|
|||
// cannot change to pending from other state
|
||||
// setPending();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -284,6 +284,28 @@
|
|||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rest-jaxrs</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rest-servlet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rest-spring</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- registry -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
|
|
@ -448,6 +470,14 @@
|
|||
</dependency>
|
||||
|
||||
<!-- Transitive dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
|
|
@ -544,6 +574,9 @@
|
|||
<include>org.apache.dubbo:dubbo-rpc-injvm</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-rest</include>
|
||||
<include>org.apache.dubbo:dubbo-rpc-triple</include>
|
||||
<include>org.apache.dubbo:dubbo-rest-jaxrs</include>
|
||||
<include>org.apache.dubbo:dubbo-rest-servlet</include>
|
||||
<include>org.apache.dubbo:dubbo-rest-spring</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-api</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-hessian2</include>
|
||||
<include>org.apache.dubbo:dubbo-serialization-fastjson2</include>
|
||||
|
|
@ -913,6 +946,27 @@
|
|||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/dubbo/internal/org.apache.dubbo.metrics.service.MetricsService</resource>
|
||||
</transformer>
|
||||
|
|
@ -980,7 +1034,7 @@
|
|||
<filter>
|
||||
<artifact>org.apache.dubbo:dubbo</artifact>
|
||||
<excludes>
|
||||
<!-- These following two line is optional, it can remove some warn log -->
|
||||
<!-- These following two line are optional, it can remove some warning log -->
|
||||
<exclude>com/**</exclude>
|
||||
<exclude>org/**</exclude>
|
||||
<!-- This one is required -->
|
||||
|
|
|
|||
|
|
@ -334,6 +334,21 @@
|
|||
<artifactId>dubbo-plugin-proxy-bytebuddy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rest-jaxrs</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rest-servlet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rest-spring</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- registry -->
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-plugin</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>dubbo-rest-jaxrs</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-triple</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
<artifactId>javax.ws.rs-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxrs</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>*</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-netty4</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-rest</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-jaxrs</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-client</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractAnnotationBaseArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public abstract class AbstractJaxrsArgumentResolver extends AbstractAnnotationBaseArgumentResolver {
|
||||
|
||||
@Override
|
||||
protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta<Annotation> ann) {
|
||||
return new NamedValueMeta(ann.getValue(), Helper.isRequired(param), Helper.defaultValue(param));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationEnum;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public enum Annotations implements AnnotationEnum {
|
||||
Path,
|
||||
HttpMethod,
|
||||
Produces,
|
||||
Consumes,
|
||||
PathParam,
|
||||
MatrixParam,
|
||||
QueryParam,
|
||||
HeaderParam,
|
||||
CookieParam,
|
||||
FormParam,
|
||||
BeanParam,
|
||||
Body("org.jboss.resteasy.annotations.Body"),
|
||||
Form("org.jboss.resteasy.annotations.Form"),
|
||||
Context("javax.ws.rs.core.Context"),
|
||||
Suspended("javax.ws.rs.container.Suspended"),
|
||||
DefaultValue,
|
||||
Encoded,
|
||||
Nonnull("javax.annotation.Nonnull");
|
||||
|
||||
private final String className;
|
||||
private Class<Annotation> type;
|
||||
|
||||
Annotations(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
Annotations() {
|
||||
className = "javax.ws.rs." + name();
|
||||
}
|
||||
|
||||
public String className() {
|
||||
return className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Annotation> type() {
|
||||
if (type == null) {
|
||||
type = loadType();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.common.utils.Pair;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.Messages;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestException;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
final class BeanArgumentBinder {
|
||||
|
||||
private final ArgumentResolver argumentResolver;
|
||||
|
||||
private final Map<Pair<Class<?>, String>, BeanMeta> cache = CollectionUtils.newConcurrentHashMap();
|
||||
|
||||
BeanArgumentBinder(FrameworkModel frameworkModel) {
|
||||
ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();
|
||||
argumentResolver = beanFactory.getOrRegisterBean(CompositeArgumentResolver.class);
|
||||
}
|
||||
|
||||
public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response) {
|
||||
try {
|
||||
return resolveArgument(parameter, request, response);
|
||||
} catch (Exception e) {
|
||||
throw new RestException(Messages.ARGUMENT_BIND_ERROR, parameter.getName(), parameter.getType(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private Object resolveArgument(ParameterMeta param, HttpRequest request, HttpResponse response) throws Exception {
|
||||
AnnotationMeta<?> form = param.findAnnotation(Annotations.Form);
|
||||
if (form != null || param.isHierarchyAnnotated(Annotations.BeanParam)) {
|
||||
String prefix = form == null ? null : form.getString("prefix");
|
||||
BeanMeta beanMeta = cache.computeIfAbsent(
|
||||
Pair.of(param.getActualType(), prefix),
|
||||
k -> new BeanMeta(param.getToolKit(), k.getValue(), k.getKey()));
|
||||
|
||||
ConstructorMeta constructor = beanMeta.constructor;
|
||||
ParameterMeta[] parameters = constructor.parameters;
|
||||
int len = parameters.length;
|
||||
Object[] args = new Object[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
args[i] = resolveArgument(parameters[i], request, response);
|
||||
}
|
||||
Object bean = constructor.newInstance(args);
|
||||
|
||||
for (FieldMeta fieldMeta : beanMeta.fields) {
|
||||
fieldMeta.set(bean, resolveArgument(fieldMeta, request, response));
|
||||
}
|
||||
|
||||
for (SetMethodMeta methodMeta : beanMeta.methods) {
|
||||
methodMeta.invoke(bean, resolveArgument(methodMeta, request, response));
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
return argumentResolver.resolve(param, request, response);
|
||||
}
|
||||
|
||||
private static class BeanMeta {
|
||||
|
||||
private final List<FieldMeta> fields = new ArrayList<>();
|
||||
private final List<SetMethodMeta> methods = new ArrayList<>();
|
||||
private final ConstructorMeta constructor;
|
||||
|
||||
BeanMeta(RestToolKit toolKit, String prefix, Class<?> type) {
|
||||
constructor = resolveConstructor(toolKit, prefix, type);
|
||||
resolveFieldAndMethod(toolKit, prefix, type);
|
||||
}
|
||||
|
||||
private ConstructorMeta resolveConstructor(RestToolKit toolKit, String prefix, Class<?> type) {
|
||||
Constructor<?>[] constructors = type.getConstructors();
|
||||
Constructor<?> ct = null;
|
||||
if (constructors.length == 1) {
|
||||
ct = constructors[0];
|
||||
} else {
|
||||
try {
|
||||
ct = type.getDeclaredConstructor();
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
}
|
||||
if (ct == null) {
|
||||
throw new IllegalArgumentException("No available default constructor found in " + type);
|
||||
}
|
||||
return new ConstructorMeta(toolKit, prefix, ct);
|
||||
}
|
||||
|
||||
private void resolveFieldAndMethod(RestToolKit toolKit, String prefix, Class<?> type) {
|
||||
if (type == Object.class) {
|
||||
return;
|
||||
}
|
||||
for (Field field : type.getDeclaredFields()) {
|
||||
int modifiers = field.getModifiers();
|
||||
if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) {
|
||||
continue;
|
||||
}
|
||||
if (field.getAnnotations().length == 0) {
|
||||
continue;
|
||||
}
|
||||
if (!field.isAccessible()) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
fields.add(new FieldMeta(toolKit, prefix, field));
|
||||
}
|
||||
for (Method method : type.getDeclaredMethods()) {
|
||||
if (method.getParameterCount() != 1) {
|
||||
continue;
|
||||
}
|
||||
int modifiers = method.getModifiers();
|
||||
if ((modifiers & (Modifier.PUBLIC | Modifier.ABSTRACT | Modifier.STATIC)) == Modifier.PUBLIC) {
|
||||
Parameter parameter = method.getParameters()[0];
|
||||
String name = method.getName();
|
||||
if (name.length() > 3 && name.startsWith("set")) {
|
||||
name = Character.toLowerCase(name.charAt(3)) + name.substring(4);
|
||||
methods.add(new SetMethodMeta(toolKit, method, parameter, prefix, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
resolveFieldAndMethod(toolKit, prefix, type.getSuperclass());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ConstructorMeta {
|
||||
|
||||
private final Constructor<?> constructor;
|
||||
private final ConstructorParameterMeta[] parameters;
|
||||
|
||||
ConstructorMeta(RestToolKit toolKit, String prefix, Constructor<?> constructor) {
|
||||
this.constructor = constructor;
|
||||
parameters = initParameters(toolKit, prefix, constructor);
|
||||
}
|
||||
|
||||
private ConstructorParameterMeta[] initParameters(RestToolKit toolKit, String prefix, Constructor<?> ct) {
|
||||
Parameter[] cps = ct.getParameters();
|
||||
int len = cps.length;
|
||||
ConstructorParameterMeta[] parameters = new ConstructorParameterMeta[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
parameters[i] = new ConstructorParameterMeta(toolKit, cps[i], prefix);
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
Object newInstance(Object[] args) throws Exception {
|
||||
return constructor.newInstance(args);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ConstructorParameterMeta extends ParameterMeta {
|
||||
|
||||
private final Parameter parameter;
|
||||
|
||||
ConstructorParameterMeta(RestToolKit toolKit, Parameter parameter, String prefix) {
|
||||
super(toolKit, prefix, parameter.isNamePresent() ? parameter.getName() : null);
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotatedElement getAnnotatedElement() {
|
||||
return parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
return parameter.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getGenericType() {
|
||||
return parameter.getParameterizedType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "ConstructorParameter{" + parameter + '}';
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FieldMeta extends ParameterMeta {
|
||||
|
||||
private final Field field;
|
||||
|
||||
FieldMeta(RestToolKit toolKit, String prefix, Field field) {
|
||||
super(toolKit, prefix, field.getName());
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
return field.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getGenericType() {
|
||||
return field.getGenericType();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotatedElement getAnnotatedElement() {
|
||||
return field;
|
||||
}
|
||||
|
||||
public void set(Object bean, Object value) throws Exception {
|
||||
field.set(bean, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "FieldParameter{" + field + '}';
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SetMethodMeta extends ParameterMeta {
|
||||
|
||||
private final Method method;
|
||||
private final Parameter parameter;
|
||||
|
||||
SetMethodMeta(RestToolKit toolKit, Method method, Parameter parameter, String prefix, String name) {
|
||||
super(toolKit, prefix, name);
|
||||
this.method = method;
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
return parameter.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getGenericType() {
|
||||
return parameter.getParameterizedType();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotatedElement getAnnotatedElement() {
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public void invoke(Object bean, Object value) throws Exception {
|
||||
method.invoke(bean, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "SetMethodParameter{" + method + '}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.BeanParam")
|
||||
public class BeanParamArgumentResolver implements AnnotationBaseArgumentResolver<Annotation> {
|
||||
|
||||
@Override
|
||||
public Class<Annotation> accept() {
|
||||
return Annotations.BeanParam.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolve(
|
||||
ParameterMeta parameter,
|
||||
AnnotationMeta<Annotation> annotation,
|
||||
HttpRequest request,
|
||||
HttpResponse response) {
|
||||
return parameter.bind(request, response);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.io.StreamUtils;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestException;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
@Activate(onClass = "org.jboss.resteasy.annotations.Body")
|
||||
public class BodyArgumentResolver implements AnnotationBaseArgumentResolver<Annotation> {
|
||||
|
||||
@Override
|
||||
public Class<Annotation> accept() {
|
||||
return Annotations.Body.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolve(
|
||||
ParameterMeta parameter,
|
||||
AnnotationMeta<Annotation> annotation,
|
||||
HttpRequest request,
|
||||
HttpResponse response) {
|
||||
Class<?> type = parameter.getActualType();
|
||||
if (type == byte[].class) {
|
||||
try {
|
||||
return StreamUtils.readBytes(request.inputStream());
|
||||
} catch (IOException e) {
|
||||
throw new RestException(e);
|
||||
}
|
||||
}
|
||||
return RequestUtils.decodeBody(request, type);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.remoting.http12.HttpCookie;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.CookieParam")
|
||||
public class CookieParamArgumentResolver extends AbstractJaxrsArgumentResolver {
|
||||
|
||||
@Override
|
||||
public Class<Annotation> accept() {
|
||||
return Annotations.CookieParam.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return request.cookie(meta.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
Collection<HttpCookie> cookies = request.cookies();
|
||||
if (cookies.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String name = meta.name();
|
||||
List<HttpCookie> result = new ArrayList<>(cookies.size());
|
||||
for (HttpCookie cookie : cookies) {
|
||||
if (name.equals(cookie.name())) {
|
||||
result.add(cookie);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
Collection<HttpCookie> cookies = request.cookies();
|
||||
if (cookies.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, List<HttpCookie>> mapValue = CollectionUtils.newLinkedHashMap(cookies.size());
|
||||
for (HttpCookie cookie : cookies) {
|
||||
mapValue.computeIfAbsent(cookie.name(), k -> new ArrayList<>()).add(cookie);
|
||||
}
|
||||
return mapValue;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.io.StreamUtils;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestException;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Activate(order = Integer.MAX_VALUE - 10000, onClass = "javax.ws.rs.Path")
|
||||
public class FallbackArgumentResolver extends AbstractArgumentResolver {
|
||||
|
||||
@Override
|
||||
public boolean accept(ParameterMeta param) {
|
||||
return param.getToolKit().getDialect() == RestConstants.DIALECT_JAXRS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NamedValueMeta createNamedValueMeta(ParameterMeta param) {
|
||||
return new NamedValueMeta(param.isAnnotated(Annotations.Nonnull), Helper.defaultValue(param));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
Object value = RequestUtils.decodeBody(request, meta.type());
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
if (meta.parameterMeta().isSimple()) {
|
||||
return request.parameter(meta.name());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
Class<?> type = meta.type();
|
||||
if (type == byte[].class) {
|
||||
try {
|
||||
return StreamUtils.readBytes(request.inputStream());
|
||||
} catch (IOException e) {
|
||||
throw new RestException(e);
|
||||
}
|
||||
}
|
||||
Object value = RequestUtils.decodeBody(request, meta.type());
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
if (TypeUtils.isSimpleProperty(meta.nestedType(0))) {
|
||||
return request.parameterValues(meta.name());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
Object value = RequestUtils.decodeBody(request, meta.type());
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
if (TypeUtils.isSimpleProperty(meta.nestedType(1))) {
|
||||
return RequestUtils.getParametersMap(request);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
@Activate(onClass = "org.jboss.resteasy.annotations.Form")
|
||||
public class FormArgumentResolver implements AnnotationBaseArgumentResolver<Annotation> {
|
||||
@Override
|
||||
public Class<Annotation> accept() {
|
||||
return Annotations.Form.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolve(
|
||||
ParameterMeta parameter,
|
||||
AnnotationMeta<Annotation> annotation,
|
||||
HttpRequest request,
|
||||
HttpResponse response) {
|
||||
return parameter.bind(request, response);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
* TODO: support nested values: (e.g., 'telephoneNumbers[0].countryCode' 'address[INVOICE].street')
|
||||
*/
|
||||
@Activate(onClass = "javax.ws.rs.FormParam")
|
||||
public class FormParamArgumentResolver extends AbstractJaxrsArgumentResolver {
|
||||
|
||||
@Override
|
||||
public Class<Annotation> accept() {
|
||||
return Annotations.FormParam.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return CollectionUtils.first(request.formParameterValues(getFullName(meta)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return request.formParameterValues(getFullName(meta));
|
||||
}
|
||||
|
||||
private String getFullName(NamedValueMeta meta) {
|
||||
String prefix = meta.parameterMeta().getPrefix();
|
||||
return prefix == null ? meta.name() : prefix + '.' + meta.name();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.HeaderParam")
|
||||
public class HeaderParamArgumentResolver extends AbstractJaxrsArgumentResolver {
|
||||
|
||||
@Override
|
||||
public Class<Annotation> accept() {
|
||||
return Annotations.HeaderParam.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return request.header(meta.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return request.headerValues(meta.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return request.headers();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.remoting.http12.HttpCookie;
|
||||
import org.apache.dubbo.remoting.http12.HttpResult;
|
||||
import org.apache.dubbo.remoting.http12.HttpUtils;
|
||||
import org.apache.dubbo.remoting.http12.message.DefaultHttpResult.Builder;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.NewCookie;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class Helper {
|
||||
|
||||
private Helper() {}
|
||||
|
||||
public static boolean isRequired(ParameterMeta parameter) {
|
||||
return parameter.isAnnotated(Annotations.Nonnull);
|
||||
}
|
||||
|
||||
public static String defaultValue(ParameterMeta annotation) {
|
||||
AnnotationMeta<?> meta = annotation.getAnnotation(Annotations.DefaultValue);
|
||||
return meta == null ? null : meta.getValue();
|
||||
}
|
||||
|
||||
public static HttpResult<Object> toBody(Response response) {
|
||||
Builder<Object> builder = HttpResult.builder().status(response.getStatus());
|
||||
if (response.hasEntity()) {
|
||||
builder.body(response.getEntity());
|
||||
}
|
||||
builder.headers(response.getStringHeaders());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static MediaType toMediaType(String mediaType) {
|
||||
if (mediaType == null) {
|
||||
return null;
|
||||
}
|
||||
int index = mediaType.indexOf('/');
|
||||
if (index == -1) {
|
||||
return null;
|
||||
}
|
||||
return new MediaType(mediaType.substring(0, index), mediaType.substring(index + 1));
|
||||
}
|
||||
|
||||
public static String toString(MediaType mediaType) {
|
||||
return mediaType.getType() + '/' + mediaType.getSubtype();
|
||||
}
|
||||
|
||||
public static List<MediaType> toMediaTypes(String accept) {
|
||||
return HttpUtils.parseAccept(accept).stream().map(Helper::toMediaType).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static NewCookie convert(HttpCookie cookie) {
|
||||
return new NewCookie(
|
||||
cookie.name(),
|
||||
cookie.value(),
|
||||
cookie.path(),
|
||||
cookie.domain(),
|
||||
null,
|
||||
(int) cookie.maxAge(),
|
||||
cookie.secure(),
|
||||
cookie.httpOnly());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MultivaluedHashMap;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.resteasy.specimpl.ResteasyHttpHeaders;
|
||||
import org.jboss.resteasy.spi.ResteasyAsynchronousContext;
|
||||
import org.jboss.resteasy.spi.ResteasyUriInfo;
|
||||
|
||||
public final class JaxrsHttpRequestAdaptee implements org.jboss.resteasy.spi.HttpRequest {
|
||||
|
||||
private final HttpRequest request;
|
||||
|
||||
private HttpHeaders headers;
|
||||
private ResteasyUriInfo uriInfo;
|
||||
|
||||
public JaxrsHttpRequestAdaptee(HttpRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHttpHeaders() {
|
||||
HttpHeaders headers = this.headers;
|
||||
if (headers == null) {
|
||||
headers = new ResteasyHttpHeaders(new MultivaluedMapWrapper<>(request.headers()));
|
||||
this.headers = headers;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultivaluedMap<String, String> getMutableHeaders() {
|
||||
return headers.getRequestHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return request.inputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputStream(InputStream stream) {
|
||||
request.setInputStream(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResteasyUriInfo getUri() {
|
||||
ResteasyUriInfo uriInfo = this.uriInfo;
|
||||
if (uriInfo == null) {
|
||||
uriInfo = new ResteasyUriInfo(request.rawPath(), request.query(), "/");
|
||||
this.uriInfo = uriInfo;
|
||||
}
|
||||
return uriInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHttpMethod() {
|
||||
return request.method();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHttpMethod(String method) {
|
||||
request.setMethod(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequestUri(URI requestUri) throws IllegalStateException {
|
||||
String query = requestUri.getRawQuery();
|
||||
request.setUri(requestUri.getRawPath() + (query == null ? "" : '?' + query));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequestUri(URI baseUri, URI requestUri) throws IllegalStateException {
|
||||
String query = requestUri.getRawQuery();
|
||||
request.setUri(baseUri.getRawPath() + requestUri.getRawPath() + (query == null ? "" : '?' + query));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultivaluedMap<String, String> getFormParameters() {
|
||||
MultivaluedMap<String, String> result = new MultivaluedHashMap<>();
|
||||
for (String name : request.formParameterNames()) {
|
||||
List<String> values = request.formParameterValues(name);
|
||||
if (values == null) {
|
||||
continue;
|
||||
}
|
||||
for (String value : values) {
|
||||
result.add(name, RequestUtils.encodeURL(value));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultivaluedMap<String, String> getDecodedFormParameters() {
|
||||
return new MultivaluedMapWrapper<>(RequestUtils.getFormParametersMap(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String attribute) {
|
||||
return request.attribute(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, Object value) {
|
||||
request.setAttribute(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
request.removeAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getAttributeNames() {
|
||||
return Collections.enumeration(request.attributeNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResteasyAsynchronousContext getAsyncContext() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitial() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forward(String path) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wasForwarded() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.remoting.http12.HttpCookie;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.NewCookie;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
public final class JaxrsHttpResponseAdaptee implements org.jboss.resteasy.spi.HttpResponse {
|
||||
|
||||
private final HttpResponse response;
|
||||
|
||||
private MultivaluedMap<String, Object> headers;
|
||||
|
||||
public JaxrsHttpResponseAdaptee(HttpResponse response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus() {
|
||||
return response.status();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(int status) {
|
||||
response.setStatus(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public MultivaluedMap<String, Object> getOutputHeaders() {
|
||||
MultivaluedMap<String, Object> headers = this.headers;
|
||||
if (headers == null) {
|
||||
headers = new MultivaluedMapWrapper(response.headers());
|
||||
this.headers = headers;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
return response.outputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOutputStream(OutputStream os) {
|
||||
response.setOutputStream(os);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNewCookie(NewCookie cookie) {
|
||||
HttpCookie hCookie = new HttpCookie(cookie.getName(), cookie.getValue());
|
||||
hCookie.setDomain(cookie.getDomain());
|
||||
hCookie.setPath(cookie.getPath());
|
||||
hCookie.setMaxAge(cookie.getMaxAge());
|
||||
hCookie.setSecure(cookie.isSecure());
|
||||
hCookie.setHttpOnly(cookie.isHttpOnly());
|
||||
response.addCookie(hCookie);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendError(int status) {
|
||||
response.sendError(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendError(int status, String message) {
|
||||
response.sendError(status, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommitted() {
|
||||
return response.isCommitted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
response.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushBuffer() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;
|
||||
|
||||
import javax.ws.rs.core.Cookie;
|
||||
import javax.ws.rs.core.Form;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.resteasy.specimpl.ResteasyHttpHeaders;
|
||||
import org.jboss.resteasy.spi.ResteasyUriInfo;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.Path")
|
||||
public class JaxrsMiscArgumentResolver implements ArgumentResolver {
|
||||
|
||||
private static final Set<Class<?>> SUPPORTED_TYPES = new HashSet<>();
|
||||
|
||||
static {
|
||||
SUPPORTED_TYPES.add(Cookie.class);
|
||||
SUPPORTED_TYPES.add(Form.class);
|
||||
SUPPORTED_TYPES.add(HttpHeaders.class);
|
||||
SUPPORTED_TYPES.add(MediaType.class);
|
||||
SUPPORTED_TYPES.add(MultivaluedMap.class);
|
||||
SUPPORTED_TYPES.add(UriInfo.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(ParameterMeta parameter) {
|
||||
return SUPPORTED_TYPES.contains(parameter.getActualType());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public Object resolve(ParameterMeta parameter, HttpRequest request, HttpResponse response) {
|
||||
Class<?> type = parameter.getActualType();
|
||||
if (Cookie.class.isAssignableFrom(type)) {
|
||||
return Helper.convert(request.cookie(parameter.getRequiredName()));
|
||||
}
|
||||
if (Form.class.isAssignableFrom(type)) {
|
||||
return RequestUtils.getFormParametersMap(request);
|
||||
}
|
||||
if (HttpHeaders.class.isAssignableFrom(type)) {
|
||||
return new ResteasyHttpHeaders(new MultivaluedMapWrapper<>(request.headers()));
|
||||
}
|
||||
if (MediaType.class.isAssignableFrom(type)) {
|
||||
return Helper.toMediaType(request.mediaType());
|
||||
}
|
||||
if (MultivaluedMap.class.isAssignableFrom(type)) {
|
||||
return new MultivaluedMapWrapper<>((Map) RequestUtils.getParametersMap(request));
|
||||
}
|
||||
if (UriInfo.class.isAssignableFrom(type)) {
|
||||
return new ResteasyUriInfo(request.rawPath(), request.query(), "/");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping.Builder;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.ServiceVersionCondition;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationSupport;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.Path")
|
||||
public class JaxrsRequestMappingResolver implements RequestMappingResolver {
|
||||
|
||||
private final RestToolKit toolKit;
|
||||
|
||||
public JaxrsRequestMappingResolver(FrameworkModel frameworkModel) {
|
||||
toolKit = new JaxrsRestToolKit(frameworkModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestToolKit getRestToolKit() {
|
||||
return toolKit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestMapping resolve(ServiceMeta serviceMeta) {
|
||||
AnnotationMeta<?> path = serviceMeta.findAnnotation(Annotations.Path);
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
return builder(serviceMeta, path, null)
|
||||
.name(serviceMeta.getType().getSimpleName())
|
||||
.contextPath(serviceMeta.getContextPath())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestMapping resolve(MethodMeta methodMeta) {
|
||||
AnnotationMeta<?> path = methodMeta.findAnnotation(Annotations.Path);
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
AnnotationMeta<?> httpMethod = methodMeta.findMergedAnnotation(Annotations.HttpMethod);
|
||||
if (httpMethod == null) {
|
||||
return null;
|
||||
}
|
||||
ServiceMeta serviceMeta = methodMeta.getServiceMeta();
|
||||
return builder(methodMeta, path, httpMethod)
|
||||
.name(methodMeta.getMethod().getName())
|
||||
.contextPath(methodMeta.getServiceMeta().getContextPath())
|
||||
.custom(new ServiceVersionCondition(serviceMeta.getServiceGroup(), serviceMeta.getServiceVersion()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private Builder builder(AnnotationSupport meta, AnnotationMeta<?> path, AnnotationMeta<?> httpMethod) {
|
||||
Builder builder = RequestMapping.builder().path(path.getValue());
|
||||
if (httpMethod == null) {
|
||||
httpMethod = meta.findMergedAnnotation(Annotations.HttpMethod);
|
||||
}
|
||||
if (httpMethod != null) {
|
||||
builder.method(httpMethod.getValue());
|
||||
}
|
||||
AnnotationMeta<?> produces = meta.findAnnotation(Annotations.Produces);
|
||||
if (produces != null) {
|
||||
builder.produce(produces.getValueArray());
|
||||
}
|
||||
AnnotationMeta<?> consumes = meta.findAnnotation(Annotations.Consumes);
|
||||
if (consumes != null) {
|
||||
builder.consume(consumes.getValueArray());
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.Listener;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
@Activate(order = -10000, onClass = "javax.ws.rs.Path")
|
||||
public class JaxrsResponseRestFilter implements RestFilter, Listener {
|
||||
|
||||
@Override
|
||||
public void onResponse(Result result, HttpRequest request, HttpResponse response) {
|
||||
if (result.hasException()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object value = result.getValue();
|
||||
if (value instanceof Response) {
|
||||
result.setValue(Helper.toBody((Response) value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.DefaultRestToolKit;
|
||||
|
||||
final class JaxrsRestToolKit extends DefaultRestToolKit {
|
||||
|
||||
private final BeanArgumentBinder binder;
|
||||
|
||||
public JaxrsRestToolKit(FrameworkModel frameworkModel) {
|
||||
super(frameworkModel);
|
||||
binder = new BeanArgumentBinder(frameworkModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDialect() {
|
||||
return RestConstants.DIALECT_JAXRS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response) {
|
||||
return binder.bind(parameter, request, response);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.MatrixParam")
|
||||
public class MatrixParamArgumentResolver extends AbstractJaxrsArgumentResolver {
|
||||
|
||||
@Override
|
||||
public Class<Annotation> accept() {
|
||||
return Annotations.MatrixParam.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return CollectionUtils.first(doResolveCollectionValue(meta, request));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return doResolveCollectionValue(meta, request);
|
||||
}
|
||||
|
||||
private static List<String> doResolveCollectionValue(NamedValueMeta meta, HttpRequest request) {
|
||||
Map<String, String> variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
|
||||
return RequestUtils.parseMatrixVariableValues(variableMap, meta.name());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.convert.Converter;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedHashMap;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class MultivaluedMapCreationConverter implements Converter<Integer, MultivaluedMap> {
|
||||
|
||||
@Override
|
||||
public MultivaluedMap<?, ?> convert(Integer source) {
|
||||
return new MultivaluedHashMap<>(source);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import javax.ws.rs.core.AbstractMultivaluedMap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class MultivaluedMapWrapper<K, V> extends AbstractMultivaluedMap<K, V> {
|
||||
|
||||
public MultivaluedMapWrapper(Map<K, List<V>> store) {
|
||||
super(store);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.Messages;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestParameterException;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Map;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.PathParam")
|
||||
public class PathParamArgumentResolver implements AnnotationBaseArgumentResolver<Annotation> {
|
||||
|
||||
@Override
|
||||
public Class<Annotation> accept() {
|
||||
return Annotations.PathParam.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolve(
|
||||
ParameterMeta parameter,
|
||||
AnnotationMeta<Annotation> annotation,
|
||||
HttpRequest request,
|
||||
HttpResponse response) {
|
||||
Map<String, String> variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
|
||||
String name = annotation.getValue();
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
name = parameter.getRequiredName();
|
||||
}
|
||||
if (variableMap == null) {
|
||||
if (Helper.isRequired(parameter)) {
|
||||
throw new RestParameterException(Messages.ARGUMENT_VALUE_MISSING, name, parameter.getType());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
String value = variableMap.get(name);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
int index = value.indexOf(';');
|
||||
if (index != -1) {
|
||||
value = value.substring(0, index);
|
||||
}
|
||||
return parameter.isAnnotated(Annotations.Encoded) ? value : RequestUtils.decodeURL(value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.QueryParam")
|
||||
public class QueryParamArgumentResolver extends AbstractJaxrsArgumentResolver {
|
||||
|
||||
@Override
|
||||
public Class<Annotation> accept() {
|
||||
return Annotations.QueryParam.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return request.parameter(meta.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return request.parameterValues(meta.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return RequestUtils.getParametersMap(request);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;
|
||||
|
||||
import org.apache.dubbo.remoting.http12.HttpCookie;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.Helper;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.JaxrsHttpRequestAdaptee;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.JaxrsHttpResponseAdaptee;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MultivaluedMapWrapper;
|
||||
|
||||
import javax.ws.rs.container.ContainerRequestContext;
|
||||
import javax.ws.rs.core.Cookie;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Request;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.SecurityContext;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.resteasy.specimpl.RequestImpl;
|
||||
import org.jboss.resteasy.spi.ResteasyUriInfo;
|
||||
|
||||
final class ContainerRequestContextImpl implements ContainerRequestContext {
|
||||
|
||||
private final HttpRequest request;
|
||||
private final HttpResponse response;
|
||||
|
||||
private Request req;
|
||||
private MultivaluedMap<String, String> headers;
|
||||
private UriInfo uriInfo;
|
||||
|
||||
private boolean aborted;
|
||||
|
||||
public ContainerRequestContextImpl(HttpRequest request, HttpResponse response) {
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
return request.attribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getPropertyNames() {
|
||||
return request.parameterNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(String name, Object object) {
|
||||
request.setAttribute(name, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProperty(String name) {
|
||||
request.removeAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UriInfo getUriInfo() {
|
||||
UriInfo uriInfo = this.uriInfo;
|
||||
if (uriInfo == null) {
|
||||
uriInfo = new ResteasyUriInfo(request.rawPath(), request.query(), "/");
|
||||
this.uriInfo = uriInfo;
|
||||
}
|
||||
return uriInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequestUri(URI requestUri) {
|
||||
String query = requestUri.getRawQuery();
|
||||
request.setUri(requestUri.getRawPath() + (query == null ? "" : '?' + query));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequestUri(URI baseUri, URI requestUri) {
|
||||
String query = requestUri.getRawQuery();
|
||||
request.setUri(baseUri.getRawPath() + requestUri.getRawPath() + (query == null ? "" : '?' + query));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request getRequest() {
|
||||
Request req = this.req;
|
||||
if (req == null) {
|
||||
req = new RequestImpl(new JaxrsHttpRequestAdaptee(request), new JaxrsHttpResponseAdaptee(response));
|
||||
this.req = req;
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return request.method();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMethod(String method) {
|
||||
request.setMethod(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultivaluedMap<String, String> getHeaders() {
|
||||
MultivaluedMap<String, String> headers = this.headers;
|
||||
if (headers == null) {
|
||||
headers = new MultivaluedMapWrapper<>(request.headers());
|
||||
this.headers = headers;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeaderString(String name) {
|
||||
return request.header(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLanguage() {
|
||||
return request.locale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return request.contentLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaType getMediaType() {
|
||||
return Helper.toMediaType(request.mediaType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MediaType> getAcceptableMediaTypes() {
|
||||
return Helper.toMediaTypes(request.accept());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Locale> getAcceptableLanguages() {
|
||||
return request.locales();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Cookie> getCookies() {
|
||||
Collection<HttpCookie> cookies = request.cookies();
|
||||
Map<String, Cookie> result = new HashMap<>(cookies.size());
|
||||
for (HttpCookie cookie : cookies) {
|
||||
result.put(cookie.name(), Helper.convert(cookie));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("resource")
|
||||
public boolean hasEntity() {
|
||||
return request.inputStream() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getEntityStream() {
|
||||
return request.inputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntityStream(InputStream input) {
|
||||
request.setInputStream(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityContext getSecurityContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSecurityContext(SecurityContext context) {}
|
||||
|
||||
@Override
|
||||
public void abortWith(Response response) {
|
||||
this.response.setBody(Helper.toBody(response));
|
||||
aborted = true;
|
||||
}
|
||||
|
||||
public boolean isAborted() {
|
||||
return aborted;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.AbstractRestFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;
|
||||
|
||||
import javax.ws.rs.container.ContainerRequestFilter;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.container.ContainerResponseFilter")
|
||||
public class ContainerRequestFilterAdapter implements RestExtensionAdapter<ContainerRequestFilter> {
|
||||
|
||||
@Override
|
||||
public boolean accept(Object extension) {
|
||||
return extension instanceof ContainerRequestFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestFilter adapt(ContainerRequestFilter extension) {
|
||||
return new Filter(extension);
|
||||
}
|
||||
|
||||
private static final class Filter extends AbstractRestFilter<ContainerRequestFilter> {
|
||||
|
||||
public Filter(ContainerRequestFilter extension) {
|
||||
super(extension);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpRequest request, HttpResponse response, FilterChain chain) throws Exception {
|
||||
ContainerRequestContextImpl context = new ContainerRequestContextImpl(request, response);
|
||||
extension.filter(context);
|
||||
if (context.isAborted()) {
|
||||
return;
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;
|
||||
|
||||
import org.apache.dubbo.remoting.http12.HttpCookie;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.remoting.http12.HttpUtils;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.Helper;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MultivaluedMapWrapper;
|
||||
|
||||
import javax.ws.rs.container.ContainerResponseContext;
|
||||
import javax.ws.rs.core.EntityTag;
|
||||
import javax.ws.rs.core.Link;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.NewCookie;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.Response.StatusType;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import io.netty.handler.codec.DateFormatter;
|
||||
|
||||
final class ContainerResponseContextImpl implements ContainerResponseContext {
|
||||
|
||||
private final HttpRequest request;
|
||||
private final HttpResponse response;
|
||||
private final Result result;
|
||||
|
||||
private MultivaluedMap<String, String> headers;
|
||||
|
||||
public ContainerResponseContextImpl(HttpRequest request, HttpResponse response, Result result) {
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus() {
|
||||
return response.status();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(int code) {
|
||||
response.setStatus(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatusType getStatusInfo() {
|
||||
return Status.fromStatusCode(response.status());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatusInfo(StatusType statusInfo) {
|
||||
response.setStatus(statusInfo.getStatusCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public MultivaluedMap<String, Object> getHeaders() {
|
||||
return (MultivaluedMap) getStringHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultivaluedMap<String, String> getStringHeaders() {
|
||||
MultivaluedMap<String, String> headers = this.headers;
|
||||
if (headers == null) {
|
||||
headers = new MultivaluedMapWrapper<>(response.headers());
|
||||
this.headers = headers;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeaderString(String name) {
|
||||
return response.header(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAllowedMethods() {
|
||||
return Collections.singleton(request.method());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLanguage() {
|
||||
return HttpUtils.parseLocale(response.locale());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaType getMediaType() {
|
||||
return Helper.toMediaType(response.mediaType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, NewCookie> getCookies() {
|
||||
Collection<HttpCookie> cookies = request.cookies();
|
||||
Map<String, NewCookie> result = new HashMap<>(cookies.size());
|
||||
for (HttpCookie cookie : cookies) {
|
||||
result.put(cookie.name(), Helper.convert(cookie));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityTag getEntityTag() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getLastModified() {
|
||||
String value = response.header("last-modified");
|
||||
return value == null ? null : DateFormatter.parseHttpDate(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getLocation() {
|
||||
String location = response.header("location");
|
||||
return location == null ? null : URI.create(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Link> getLinks() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLink(String relation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Link getLink(String relation) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Link.Builder getLinkBuilder(String relation) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEntity() {
|
||||
return getEntity() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getEntity() {
|
||||
return result.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getEntityClass() {
|
||||
return getHandler().getMethod().getReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getEntityType() {
|
||||
return getHandler().getMethod().getGenericReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntity(Object entity) {
|
||||
result.setValue(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntity(Object entity, Annotation[] annotations, MediaType mediaType) {
|
||||
result.setValue(entity);
|
||||
response.setContentType(Helper.toString(mediaType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getEntityAnnotations() {
|
||||
return new Annotation[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getEntityStream() {
|
||||
return response.outputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntityStream(OutputStream outputStream) {
|
||||
response.setOutputStream(outputStream);
|
||||
}
|
||||
|
||||
private HandlerMeta getHandler() {
|
||||
return request.attribute(RestConstants.HANDLER_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.AbstractRestFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.Listener;
|
||||
|
||||
import javax.ws.rs.container.ContainerResponseFilter;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.container.ContainerResponseFilter")
|
||||
public class ContainerResponseFilterAdapter implements RestExtensionAdapter<ContainerResponseFilter> {
|
||||
|
||||
@Override
|
||||
public boolean accept(Object extension) {
|
||||
return extension instanceof ContainerResponseFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestFilter adapt(ContainerResponseFilter extension) {
|
||||
return new Filter(extension);
|
||||
}
|
||||
|
||||
private static final class Filter extends AbstractRestFilter<ContainerResponseFilter> implements Listener {
|
||||
|
||||
public Filter(ContainerResponseFilter extension) {
|
||||
super(extension);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Result result, HttpRequest request, HttpResponse response) throws Exception {
|
||||
extension.filter(
|
||||
new ContainerRequestContextImpl(request, response),
|
||||
new ContainerResponseContextImpl(request, response, result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.AbstractRestFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.Listener;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.Helper;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.ext.ExceptionMapper")
|
||||
public final class ExceptionMapperAdapter implements RestExtensionAdapter<ExceptionMapper<Throwable>> {
|
||||
|
||||
@Override
|
||||
public boolean accept(Object extension) {
|
||||
return extension instanceof ExceptionMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestFilter adapt(ExceptionMapper<Throwable> extension) {
|
||||
return new Filter(extension);
|
||||
}
|
||||
|
||||
private static final class Filter extends AbstractRestFilter<ExceptionMapper<Throwable>> implements Listener {
|
||||
|
||||
private final Class<?> exceptionType;
|
||||
|
||||
public Filter(ExceptionMapper<Throwable> extension) {
|
||||
super(extension);
|
||||
exceptionType = TypeUtils.getSuperGenericType(extension.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Result result, HttpRequest request, HttpResponse response) throws Exception {
|
||||
if (result.hasException()) {
|
||||
Throwable t = result.getException();
|
||||
if (exceptionType.isInstance(t)) {
|
||||
try (Response r = extension.toResponse(t)) {
|
||||
response.setBody(Helper.toBody(r));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t, HttpRequest request, HttpResponse response) {
|
||||
if (exceptionType.isInstance(t)) {
|
||||
try (Response r = extension.toResponse(t)) {
|
||||
response.setBody(Helper.toBody(r));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;
|
||||
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta;
|
||||
|
||||
import javax.ws.rs.ext.InterceptorContext;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
public abstract class InterceptorContextImpl implements InterceptorContext {
|
||||
|
||||
protected final HttpRequest request;
|
||||
|
||||
public InterceptorContextImpl(HttpRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
return request.attribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getPropertyNames() {
|
||||
return request.parameterNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(String name, Object object) {
|
||||
request.setAttribute(name, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProperty(String name) {
|
||||
request.removeAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return getHandler().getMethod().getRealAnnotations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnnotations(Annotation[] annotations) {}
|
||||
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
return getHandler().getMethod().getReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(Class<?> type) {}
|
||||
|
||||
@Override
|
||||
public Type getGenericType() {
|
||||
return getHandler().getMethod().getGenericReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGenericType(Type genericType) {}
|
||||
|
||||
private HandlerMeta getHandler() {
|
||||
return request.attribute(RestConstants.HANDLER_ATTRIBUTE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.AbstractRestFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;
|
||||
|
||||
import javax.ws.rs.ext.ReaderInterceptor;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.ext.ReaderInterceptor")
|
||||
public final class ReadInterceptorAdapter implements RestExtensionAdapter<ReaderInterceptor> {
|
||||
|
||||
@Override
|
||||
public boolean accept(Object extension) {
|
||||
return extension instanceof ReaderInterceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestFilter adapt(ReaderInterceptor extension) {
|
||||
return new Filter(extension);
|
||||
}
|
||||
|
||||
private static final class Filter extends AbstractRestFilter<ReaderInterceptor> {
|
||||
|
||||
public Filter(ReaderInterceptor extension) {
|
||||
super(extension);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpRequest request, HttpResponse response, FilterChain chain) throws Exception {
|
||||
extension.aroundReadFrom(new ReaderInterceptorContextImpl(request, response, chain));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;
|
||||
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.FilterChain;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.Helper;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MultivaluedMapWrapper;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.ext.ReaderInterceptorContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
final class ReaderInterceptorContextImpl extends InterceptorContextImpl implements ReaderInterceptorContext {
|
||||
|
||||
private final HttpResponse response;
|
||||
private final FilterChain chain;
|
||||
|
||||
private MultivaluedMap<String, String> headers;
|
||||
|
||||
public ReaderInterceptorContextImpl(HttpRequest request, HttpResponse response, FilterChain chain) {
|
||||
super(request);
|
||||
this.response = response;
|
||||
this.chain = chain;
|
||||
headers = new MultivaluedMapWrapper<>(request.headers());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object proceed() throws IOException, WebApplicationException {
|
||||
try {
|
||||
chain.doFilter(request, response);
|
||||
} catch (RuntimeException | IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new WebApplicationException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return request.inputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputStream(InputStream is) {
|
||||
request.setInputStream(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultivaluedMap<String, String> getHeaders() {
|
||||
MultivaluedMap<String, String> headers = this.headers;
|
||||
if (headers == null) {
|
||||
headers = new MultivaluedMapWrapper<>(request.headers());
|
||||
this.headers = headers;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaType getMediaType() {
|
||||
return Helper.toMediaType(request.mediaType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMediaType(MediaType mediaType) {
|
||||
request.setContentType(Helper.toString(mediaType));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.AbstractRestFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter.Listener;
|
||||
|
||||
import javax.ws.rs.ext.WriterInterceptor;
|
||||
|
||||
@Activate(onClass = "javax.ws.rs.ext.WriterInterceptor")
|
||||
public final class WriterInterceptorAdapter implements RestExtensionAdapter<WriterInterceptor> {
|
||||
|
||||
@Override
|
||||
public boolean accept(Object extension) {
|
||||
return extension instanceof WriterInterceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestFilter adapt(WriterInterceptor extension) {
|
||||
return new Filter(extension);
|
||||
}
|
||||
|
||||
private static final class Filter extends AbstractRestFilter<WriterInterceptor> implements Listener {
|
||||
|
||||
public Filter(WriterInterceptor extension) {
|
||||
super(extension);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Result result, HttpRequest request, HttpResponse response) throws Exception {
|
||||
extension.aroundWriteTo(new WriterInterceptorContextImpl(request, response, result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;
|
||||
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.Helper;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MultivaluedMapWrapper;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.ext.WriterInterceptorContext;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
final class WriterInterceptorContextImpl extends InterceptorContextImpl implements WriterInterceptorContext {
|
||||
|
||||
private final HttpResponse response;
|
||||
private final Result result;
|
||||
|
||||
private MultivaluedMap<String, Object> headers;
|
||||
|
||||
public WriterInterceptorContextImpl(HttpRequest request, HttpResponse response, Result result) {
|
||||
super(request);
|
||||
this.response = response;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void proceed() throws WebApplicationException {}
|
||||
|
||||
@Override
|
||||
public Object getEntity() {
|
||||
return result.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntity(Object entity) {
|
||||
result.setValue(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
return response.outputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOutputStream(OutputStream os) {
|
||||
response.setOutputStream(os);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public MultivaluedMap<String, Object> getHeaders() {
|
||||
MultivaluedMap<String, Object> headers = this.headers;
|
||||
if (headers == null) {
|
||||
headers = new MultivaluedMapWrapper(response.headers());
|
||||
this.headers = headers;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaType getMediaType() {
|
||||
return Helper.toMediaType(response.mediaType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMediaType(MediaType mediaType) {
|
||||
response.setContentType(Helper.toString(mediaType));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
integer-to-multi-valued-map=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MultivaluedMapCreationConverter
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
jaxrs-path-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.PathParamArgumentResolver
|
||||
jaxrs-matrix-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.MatrixParamArgumentResolver
|
||||
jaxrs-query-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.QueryParamArgumentResolver
|
||||
jaxrs-header-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.HeaderParamArgumentResolver
|
||||
jaxrs-cookie-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.CookieParamArgumentResolver
|
||||
jaxrs-form-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.FormParamArgumentResolver
|
||||
jaxrs-bean-param=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.BeanParamArgumentResolver
|
||||
jaxrs-body=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.BodyArgumentResolver
|
||||
jaxrs-form=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.FormArgumentResolver
|
||||
jaxrs-misc=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.JaxrsMiscArgumentResolver
|
||||
jaxrs-fallback=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.FallbackArgumentResolver
|
||||
|
|
@ -0,0 +1 @@
|
|||
jaxrs-response=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.JaxrsResponseRestFilter
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
jaxrs-request-filter=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter.ContainerRequestFilterAdapter
|
||||
jaxrs-response-filter=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter.ContainerResponseFilterAdapter
|
||||
jaxrs-read-interceptor=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter.ReadInterceptorAdapter
|
||||
jaxrs-writer-interceptor=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter.WriterInterceptorAdapter
|
||||
jaxrs-exception-mapper=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter.ExceptionMapperAdapter
|
||||
|
|
@ -0,0 +1 @@
|
|||
jaxrs=org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.JaxrsRequestMappingResolver
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.FormParam;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
import org.jboss.resteasy.annotations.Form;
|
||||
|
||||
@Path("/demoService")
|
||||
public interface DemoService {
|
||||
@GET
|
||||
@Path("/hello")
|
||||
Integer hello(@QueryParam("a") Integer a, @QueryParam("b") Integer b);
|
||||
|
||||
@GET
|
||||
@Path("/error")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
@Produces({MediaType.TEXT_PLAIN})
|
||||
String error();
|
||||
|
||||
@POST
|
||||
@Path("/say")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
String sayHello(String name);
|
||||
|
||||
@POST
|
||||
@Path("number")
|
||||
Long testFormBody(@FormParam("number") Long number);
|
||||
|
||||
boolean isCalled();
|
||||
|
||||
@GET
|
||||
@Path("/primitive")
|
||||
int primitiveInt(@QueryParam("a") int a, @QueryParam("b") int b);
|
||||
|
||||
@GET
|
||||
@Path("/primitiveLong")
|
||||
long primitiveLong(@QueryParam("a") long a, @QueryParam("b") Long b);
|
||||
|
||||
@GET
|
||||
@Path("/primitiveByte")
|
||||
long primitiveByte(@QueryParam("a") byte a, @QueryParam("b") Long b);
|
||||
|
||||
@POST
|
||||
@Path("/primitiveShort")
|
||||
long primitiveShort(@QueryParam("a") short a, @QueryParam("b") Long b, int c);
|
||||
|
||||
@GET
|
||||
@Path("/request")
|
||||
void request(DefaultFullHttpRequest defaultFullHttpRequest);
|
||||
|
||||
@GET
|
||||
@Path("testMapParam")
|
||||
@Produces({MediaType.TEXT_PLAIN})
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
String testMapParam(@QueryParam("test") Map<String, String> params);
|
||||
|
||||
@GET
|
||||
@Path("testMapHeader")
|
||||
@Produces({MediaType.TEXT_PLAIN})
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
String testMapHeader(@HeaderParam("test") Map<String, String> headers);
|
||||
|
||||
@POST
|
||||
@Path("testMapForm")
|
||||
@Produces({MediaType.APPLICATION_JSON})
|
||||
@Consumes({MediaType.APPLICATION_FORM_URLENCODED})
|
||||
List<String> testMapForm(MultivaluedMap<String, String> params);
|
||||
|
||||
@POST
|
||||
@Path("/header")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
String header(@HeaderParam("header") String header);
|
||||
|
||||
@POST
|
||||
@Path("/headerInt")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
int headerInt(@HeaderParam("header") int header);
|
||||
|
||||
@POST
|
||||
@Path("/noStringParam")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
String noStringParam(@QueryParam("param") String param);
|
||||
|
||||
@POST
|
||||
@Path("/noStringHeader")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
String noStringHeader(@HeaderParam("header") String header);
|
||||
|
||||
@POST
|
||||
@Path("/noIntHeader")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
int noIntHeader(int header);
|
||||
|
||||
@POST
|
||||
@Path("/noIntParam")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
int noIntParam(int header);
|
||||
|
||||
@POST
|
||||
@Path("/noBodyArg")
|
||||
@Consumes({MediaType.APPLICATION_JSON})
|
||||
User noBodyArg(User user);
|
||||
|
||||
@POST
|
||||
@Path("/list")
|
||||
List<User> list(List<User> users);
|
||||
|
||||
@POST
|
||||
@Path("/set")
|
||||
Set<User> set(Set<User> users);
|
||||
|
||||
@POST
|
||||
@Path("/array")
|
||||
User[] array(User[] users);
|
||||
|
||||
@POST
|
||||
@Path("/stringMap")
|
||||
Map<String, User> stringMap(Map<String, User> userMap);
|
||||
|
||||
@POST
|
||||
@Path("/map")
|
||||
Map<User, User> userMap(Map<User, User> userMap);
|
||||
|
||||
@POST
|
||||
@Path("/formBody")
|
||||
User formBody(@Form User user);
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible;
|
||||
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
|
||||
@Path("/demoService")
|
||||
public class DemoServiceImpl implements DemoService {
|
||||
private static Map<String, Object> context;
|
||||
private boolean called;
|
||||
|
||||
@POST
|
||||
@Path("/say")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
@Override
|
||||
public String sayHello(String name) {
|
||||
called = true;
|
||||
return "Hello, " + name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long testFormBody(Long number) {
|
||||
return number;
|
||||
}
|
||||
|
||||
public boolean isCalled() {
|
||||
return called;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int primitiveInt(int a, int b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long primitiveLong(long a, Long b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long primitiveByte(byte a, Long b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long primitiveShort(short a, Long b, int c) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void request(DefaultFullHttpRequest defaultFullHttpRequest) {}
|
||||
|
||||
@Override
|
||||
public String testMapParam(Map<String, String> params) {
|
||||
return params.get("param");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String testMapHeader(Map<String, String> headers) {
|
||||
return headers.get("header");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> testMapForm(MultivaluedMap<String, String> params) {
|
||||
return params.get("form");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String header(String header) {
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int headerInt(int header) {
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String noStringParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String noStringHeader(String header) {
|
||||
return header;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/noIntHeader")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
@Override
|
||||
public int noIntHeader(@HeaderParam("header") int header) {
|
||||
return header;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/noIntParam")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
@Override
|
||||
public int noIntParam(@QueryParam("header") int header) {
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User noBodyArg(User user) {
|
||||
return user;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/hello")
|
||||
@Override
|
||||
public Integer hello(@QueryParam("a") Integer a, @QueryParam("b") Integer b) {
|
||||
context = RpcContext.getServerAttachment().getObjectAttachments();
|
||||
return a + b;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/error")
|
||||
@Override
|
||||
public String error() {
|
||||
throw new RuntimeException("test error");
|
||||
}
|
||||
|
||||
public static Map<String, Object> getAttachments() {
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<User> list(List<User> users) {
|
||||
return users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<User> set(Set<User> users) {
|
||||
return users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User[] array(User[] users) {
|
||||
return users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, User> stringMap(Map<String, User> userMap) {
|
||||
return userMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<User, User> userMap(Map<User, User> userMap) {
|
||||
return userMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User formBody(User user) {
|
||||
user.setName("formBody");
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,563 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.rpc.Exporter;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Protocol;
|
||||
import org.apache.dubbo.rpc.ProxyFactory;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.model.ModuleServiceRepository;
|
||||
import org.apache.dubbo.rpc.model.ProviderModel;
|
||||
import org.apache.dubbo.rpc.model.ServiceDescriptor;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter.TestContainerRequestFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter.TraceFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter.TraceRequestAndResponseFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.intercept.DynamicTraceInterceptor;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.AnotherUserRestService;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.AnotherUserRestServiceImpl;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.HttpMethodService;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.HttpMethodServiceImpl;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.RestDemoForTestException;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.RestDemoService;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest.RestDemoServiceImpl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.apache.dubbo.remoting.Constants.SERVER_KEY;
|
||||
import static org.apache.dubbo.rpc.protocol.tri.rest.RestConstants.EXTENSION_KEY;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
class JaxrsRestProtocolTest {
|
||||
private final Protocol tProtocol =
|
||||
ApplicationModel.defaultModel().getExtensionLoader(Protocol.class).getExtension("tri");
|
||||
private final Protocol protocol =
|
||||
ApplicationModel.defaultModel().getExtensionLoader(Protocol.class).getExtension("rest");
|
||||
private final ProxyFactory proxy = ApplicationModel.defaultModel()
|
||||
.getExtensionLoader(ProxyFactory.class)
|
||||
.getAdaptiveExtension();
|
||||
|
||||
private final int availablePort = NetUtils.getAvailablePort();
|
||||
private final URL exportUrl =
|
||||
URL.valueOf("tri://127.0.0.1:" + availablePort + "/rest?interface=" + DemoService.class.getName());
|
||||
|
||||
private static final String SERVER = "netty4";
|
||||
|
||||
private final ModuleServiceRepository repository =
|
||||
ApplicationModel.defaultModel().getDefaultModule().getServiceRepository();
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
tProtocol.destroy();
|
||||
protocol.destroy();
|
||||
FrameworkModel.destroyAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRestProtocol() {
|
||||
URL url = URL.valueOf("tri://127.0.0.1:" + NetUtils.getAvailablePort() + "/?version=1.0.0&interface="
|
||||
+ DemoService.class.getName());
|
||||
|
||||
DemoServiceImpl server = new DemoServiceImpl();
|
||||
|
||||
url = registerProvider(url, server, DemoService.class);
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, url));
|
||||
|
||||
Invoker<DemoService> invoker = protocol.refer(DemoService.class, url);
|
||||
Assertions.assertFalse(server.isCalled());
|
||||
|
||||
DemoService client = proxy.getProxy(invoker);
|
||||
String result = client.sayHello("haha");
|
||||
Assertions.assertTrue(server.isCalled());
|
||||
Assertions.assertEquals("Hello, haha", result);
|
||||
|
||||
String header = client.header("header test");
|
||||
Assertions.assertEquals("header test", header);
|
||||
|
||||
Assertions.assertEquals(1, client.headerInt(1));
|
||||
invoker.destroy();
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAnotherUserRestProtocolByDifferentRestClient() {
|
||||
testAnotherUserRestProtocol(org.apache.dubbo.remoting.Constants.OK_HTTP);
|
||||
testAnotherUserRestProtocol(org.apache.dubbo.remoting.Constants.APACHE_HTTP_CLIENT);
|
||||
testAnotherUserRestProtocol(org.apache.dubbo.remoting.Constants.URL_CONNECTION);
|
||||
}
|
||||
|
||||
void testAnotherUserRestProtocol(String restClient) {
|
||||
URL url = URL.valueOf("tri://127.0.0.1:" + NetUtils.getAvailablePort() + "/?version=1.0.0&interface="
|
||||
+ AnotherUserRestService.class.getName() + "&" + org.apache.dubbo.remoting.Constants.CLIENT_KEY + "="
|
||||
+ restClient);
|
||||
|
||||
AnotherUserRestServiceImpl server = new AnotherUserRestServiceImpl();
|
||||
|
||||
url = this.registerProvider(url, server, AnotherUserRestService.class);
|
||||
|
||||
Exporter<AnotherUserRestService> exporter =
|
||||
tProtocol.export(proxy.getInvoker(server, AnotherUserRestService.class, url));
|
||||
Invoker<AnotherUserRestService> invoker = protocol.refer(AnotherUserRestService.class, url);
|
||||
|
||||
AnotherUserRestService client = proxy.getProxy(invoker);
|
||||
User result = client.getUser(123l);
|
||||
|
||||
Assertions.assertEquals(123l, result.getId());
|
||||
|
||||
result.setName("dubbo");
|
||||
Assertions.assertEquals(123l, client.registerUser(result).getId());
|
||||
|
||||
Assertions.assertEquals("context", client.getContext());
|
||||
|
||||
byte[] bytes = {1, 2, 3, 4};
|
||||
Assertions.assertTrue(Arrays.equals(bytes, client.bytes(bytes)));
|
||||
|
||||
Assertions.assertEquals(1l, client.number(1l));
|
||||
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
map.put("headers", "h1");
|
||||
Assertions.assertEquals("h1", client.headerMap(map));
|
||||
Assertions.assertEquals(null, client.headerMap(null));
|
||||
|
||||
invoker.destroy();
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRestProtocolWithContextPath() {
|
||||
DemoServiceImpl server = new DemoServiceImpl();
|
||||
Assertions.assertFalse(server.isCalled());
|
||||
int port = NetUtils.getAvailablePort();
|
||||
URL url = URL.valueOf(
|
||||
"tri://127.0.0.1:" + port + "/a/b/c?version=1.0.0&interface=" + DemoService.class.getName());
|
||||
|
||||
url = this.registerProvider(url, server, DemoService.class);
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, url));
|
||||
|
||||
url = URL.valueOf(
|
||||
"rest://127.0.0.1:" + port + "/a/b/c/?version=1.0.0&interface=" + DemoService.class.getName());
|
||||
Invoker<DemoService> invoker = protocol.refer(DemoService.class, url);
|
||||
DemoService client = proxy.getProxy(invoker);
|
||||
String result = client.sayHello("haha");
|
||||
Assertions.assertTrue(server.isCalled());
|
||||
Assertions.assertEquals("Hello, haha", result);
|
||||
invoker.destroy();
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExport() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL url = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
RpcContext.getClientAttachment().setAttachment("timeout", "20000");
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, url));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, url));
|
||||
|
||||
Integer echoString = demoService.hello(1, 2);
|
||||
assertThat(echoString, is(3));
|
||||
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNettyServer() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL url = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
URL nettyUrl = url.addParameter(SERVER_KEY, SERVER);
|
||||
Exporter<DemoService> exporter =
|
||||
tProtocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, nettyUrl));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
|
||||
|
||||
Integer echoString = demoService.hello(10, 10);
|
||||
assertThat(echoString, is(20));
|
||||
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInvoke() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL url = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, url));
|
||||
|
||||
RpcInvocation rpcInvocation = new RpcInvocation(
|
||||
"hello", DemoService.class.getName(), "", new Class[] {Integer.class, Integer.class}, new Integer[] {
|
||||
2, 3
|
||||
});
|
||||
rpcInvocation.setTargetServiceUniqueName(url.getServiceKey());
|
||||
|
||||
Result result = exporter.getInvoker().invoke(rpcInvocation);
|
||||
assertThat(result.getValue(), CoreMatchers.<Object>is(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultPort() {
|
||||
assertThat(protocol.getDefaultPort(), is(80));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRestExceptionMapper() {
|
||||
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL url = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
URL exceptionUrl = url.addParameter(EXTENSION_KEY, ResteasyExceptionMapper.class.getName());
|
||||
|
||||
tProtocol.export(proxy.getInvoker(server, DemoService.class, exceptionUrl));
|
||||
|
||||
DemoService referDemoService = this.proxy.getProxy(protocol.refer(DemoService.class, exceptionUrl));
|
||||
|
||||
Assertions.assertEquals("test-exception", referDemoService.error());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFormConsumerParser() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
|
||||
|
||||
Long number = demoService.testFormBody(18l);
|
||||
Assertions.assertEquals(18l, number);
|
||||
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void test404() {
|
||||
Assertions.assertThrows(RpcException.class, () -> {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
URL referUrl = URL.valueOf(
|
||||
"tri://127.0.0.1:" + availablePort + "/rest?interface=" + RestDemoForTestException.class.getName());
|
||||
|
||||
RestDemoForTestException restDemoForTestException =
|
||||
this.proxy.getProxy(protocol.refer(RestDemoForTestException.class, referUrl));
|
||||
|
||||
restDemoForTestException.test404();
|
||||
|
||||
exporter.unexport();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void test400() {
|
||||
Assertions.assertThrows(RpcException.class, () -> {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
URL referUrl = URL.valueOf(
|
||||
"tri://127.0.0.1:" + availablePort + "/rest?interface=" + RestDemoForTestException.class.getName());
|
||||
|
||||
RestDemoForTestException restDemoForTestException =
|
||||
this.proxy.getProxy(protocol.refer(RestDemoForTestException.class, referUrl));
|
||||
|
||||
restDemoForTestException.test400("abc", "edf");
|
||||
|
||||
exporter.unexport();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPrimitive() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
|
||||
|
||||
Integer result = demoService.primitiveInt(1, 2);
|
||||
Long resultLong = demoService.primitiveLong(1, 2l);
|
||||
long resultByte = demoService.primitiveByte((byte) 1, 2l);
|
||||
long resultShort = demoService.primitiveShort((short) 1, 2l, 1);
|
||||
|
||||
assertThat(result, is(3));
|
||||
assertThat(resultShort, is(3l));
|
||||
assertThat(resultLong, is(3l));
|
||||
assertThat(resultByte, is(3l));
|
||||
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMapParam() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("param", "P1");
|
||||
;
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("header", "H1");
|
||||
|
||||
Assertions.assertEquals("P1", demoService.testMapParam(params));
|
||||
Assertions.assertEquals("H1", demoService.testMapHeader(headers));
|
||||
|
||||
MultivaluedMapImpl<String, String> forms = new MultivaluedMapImpl<>();
|
||||
forms.put("form", Arrays.asList("F1"));
|
||||
|
||||
Assertions.assertEquals(Arrays.asList("F1"), demoService.testMapForm(forms));
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoArgParam() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL url = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
URL nettyUrl = url.addParameter(SERVER_KEY, SERVER);
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
|
||||
|
||||
Assertions.assertEquals(null, demoService.noStringHeader(null));
|
||||
Assertions.assertEquals(null, demoService.noStringParam(null));
|
||||
/* Assertions.assertThrows(RpcException.class, () -> {
|
||||
demoService.noIntHeader(1);
|
||||
});
|
||||
|
||||
Assertions.assertThrows(RpcException.class, () -> {
|
||||
demoService.noIntParam(1);
|
||||
});*/
|
||||
|
||||
Assertions.assertEquals(null, demoService.noBodyArg(null));
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHttpMethods() {
|
||||
testHttpMethod(org.apache.dubbo.remoting.Constants.OK_HTTP);
|
||||
testHttpMethod(org.apache.dubbo.remoting.Constants.APACHE_HTTP_CLIENT);
|
||||
testHttpMethod(org.apache.dubbo.remoting.Constants.URL_CONNECTION);
|
||||
}
|
||||
|
||||
void testHttpMethod(String restClient) {
|
||||
HttpMethodService server = new HttpMethodServiceImpl();
|
||||
|
||||
URL url = URL.valueOf("tri://127.0.0.1:" + NetUtils.getAvailablePort() + "/?version=1.0.0&interface="
|
||||
+ HttpMethodService.class.getName() + "&"
|
||||
+ org.apache.dubbo.remoting.Constants.CLIENT_KEY + "=" + restClient);
|
||||
url = this.registerProvider(url, server, HttpMethodService.class);
|
||||
Exporter<HttpMethodService> exporter = tProtocol.export(proxy.getInvoker(server, HttpMethodService.class, url));
|
||||
|
||||
HttpMethodService demoService = this.proxy.getProxy(protocol.refer(HttpMethodService.class, url));
|
||||
|
||||
String expect = "hello";
|
||||
Assertions.assertEquals(null, demoService.sayHelloHead());
|
||||
Assertions.assertEquals(expect, demoService.sayHelloDelete("hello"));
|
||||
Assertions.assertEquals(expect, demoService.sayHelloGet("hello"));
|
||||
Assertions.assertEquals(expect, demoService.sayHelloOptions("hello"));
|
||||
// Assertions.assertEquals(expect, demoService.sayHelloPatch("hello"));
|
||||
Assertions.assertEquals(expect, demoService.sayHelloPost("hello"));
|
||||
Assertions.assertEquals(expect, demoService.sayHelloPut("hello"));
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void test405() {
|
||||
int availablePort = NetUtils.getAvailablePort();
|
||||
URL url = URL.valueOf("tri://127.0.0.1:" + availablePort
|
||||
+ "/?version=1.0.0&interface=org.apache.dubbo.rpc.protocol.rest.rest.RestDemoService&");
|
||||
|
||||
RestDemoServiceImpl server = new RestDemoServiceImpl();
|
||||
|
||||
url = this.registerProvider(url, server, RestDemoService.class);
|
||||
|
||||
Exporter<RestDemoService> exporter = tProtocol.export(proxy.getInvoker(server, RestDemoService.class, url));
|
||||
|
||||
URL consumer = URL.valueOf("rest://127.0.0.1:" + availablePort + "/?version=1.0.0&interface="
|
||||
+ RestDemoForTestException.class.getName());
|
||||
|
||||
consumer = this.registerProvider(consumer, server, RestDemoForTestException.class);
|
||||
|
||||
Invoker<RestDemoForTestException> invoker = protocol.refer(RestDemoForTestException.class, consumer);
|
||||
|
||||
RestDemoForTestException client = proxy.getProxy(invoker);
|
||||
|
||||
Assertions.assertThrows(RpcException.class, () -> {
|
||||
client.testMethodDisallowed("aaa");
|
||||
});
|
||||
|
||||
invoker.destroy();
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testContainerRequestFilter() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL url = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
URL nettyUrl = url.addParameter(EXTENSION_KEY, TestContainerRequestFilter.class.getName());
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
|
||||
|
||||
Assertions.assertEquals("return-success", demoService.sayHello("hello"));
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIntercept() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL url = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
URL nettyUrl = url.addParameter(EXTENSION_KEY, DynamicTraceInterceptor.class.getName());
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
|
||||
|
||||
Assertions.assertEquals("intercept", demoService.sayHello("hello"));
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResponseFilter() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL url = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
URL nettyUrl = url.addParameter(EXTENSION_KEY, TraceFilter.class.getName());
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
|
||||
|
||||
Assertions.assertEquals("response-filter", demoService.sayHello("hello"));
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCollectionResult() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
|
||||
|
||||
Assertions.assertEquals(
|
||||
User.getInstance(),
|
||||
demoService.list(Arrays.asList(User.getInstance())).get(0));
|
||||
|
||||
HashSet<User> objects = new HashSet<>();
|
||||
objects.add(User.getInstance());
|
||||
Assertions.assertEquals(User.getInstance(), new ArrayList<>(demoService.set(objects)).get(0));
|
||||
|
||||
Assertions.assertEquals(User.getInstance(), demoService.array(objects.toArray(new User[0]))[0]);
|
||||
|
||||
Map<String, User> map = new HashMap<>();
|
||||
map.put("map", User.getInstance());
|
||||
Assertions.assertEquals(User.getInstance(), demoService.stringMap(map).get("map"));
|
||||
|
||||
// Map<User, User> maps = new HashMap<>();
|
||||
// maps.put(User.getInstance(), User.getInstance());
|
||||
// Assertions.assertEquals(User.getInstance(), demoService.userMap(maps).get(User.getInstance()));
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRequestAndResponseFilter() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL exportUrl = URL.valueOf("tri://127.0.0.1:" + availablePort + "/rest?interface="
|
||||
+ DemoService.class.getName() + "&extension=" + TraceRequestAndResponseFilter.class.getName());
|
||||
|
||||
URL nettyUrl = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
|
||||
|
||||
Assertions.assertEquals("header-result", demoService.sayHello("hello"));
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFormBody() {
|
||||
DemoService server = new DemoServiceImpl();
|
||||
|
||||
URL url = this.registerProvider(exportUrl, server, DemoService.class);
|
||||
|
||||
URL nettyUrl = url.addParameter(SERVER_KEY, SERVER);
|
||||
|
||||
Exporter<DemoService> exporter = tProtocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl));
|
||||
|
||||
DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl));
|
||||
|
||||
User user = demoService.formBody(User.getInstance());
|
||||
|
||||
Assertions.assertEquals("formBody", user.getName());
|
||||
exporter.unexport();
|
||||
}
|
||||
|
||||
private URL registerProvider(URL url, Object impl, Class<?> interfaceClass) {
|
||||
ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);
|
||||
ProviderModel providerModel = new ProviderModel(url.getServiceKey(), impl, serviceDescriptor, null, null);
|
||||
repository.registerProvider(providerModel);
|
||||
return url.setServiceModel(providerModel);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
|
||||
public class ResteasyExceptionMapper implements ExceptionMapper<RuntimeException> {
|
||||
@Override
|
||||
public Response toResponse(RuntimeException exception) {
|
||||
return Response.status(200).entity("test-exception").build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* User Entity
|
||||
*
|
||||
* @since 2.7.6
|
||||
*/
|
||||
public class User implements Serializable {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer age;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(Integer age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public static User getInstance() {
|
||||
User user = new User();
|
||||
user.setAge(18);
|
||||
user.setName("dubbo");
|
||||
user.setId(404l);
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
User user = (User) o;
|
||||
return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(age, user.age);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name, age);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter;
|
||||
|
||||
import javax.annotation.Priority;
|
||||
import javax.ws.rs.Priorities;
|
||||
import javax.ws.rs.container.ContainerRequestContext;
|
||||
import javax.ws.rs.container.ContainerRequestFilter;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Priority(Priorities.USER)
|
||||
public class TestContainerRequestFilter implements ContainerRequestFilter {
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext) throws IOException {
|
||||
|
||||
requestContext.abortWith(Response.status(200).entity("return-success").build());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter;
|
||||
|
||||
import javax.annotation.Priority;
|
||||
import javax.ws.rs.Priorities;
|
||||
import javax.ws.rs.container.ContainerRequestContext;
|
||||
import javax.ws.rs.container.ContainerRequestFilter;
|
||||
import javax.ws.rs.container.ContainerResponseContext;
|
||||
import javax.ws.rs.container.ContainerResponseFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Priority(Priorities.USER)
|
||||
public class TraceFilter implements ContainerRequestFilter, ContainerResponseFilter {
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext) throws IOException {
|
||||
System.out.println(
|
||||
"Request filter invoked: " + requestContext.getUriInfo().getAbsolutePath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filter(
|
||||
ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext)
|
||||
throws IOException {
|
||||
containerResponseContext.setEntity("response-filter");
|
||||
System.out.println("Response filter invoked.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.filter;
|
||||
|
||||
import javax.annotation.Priority;
|
||||
import javax.ws.rs.Priorities;
|
||||
import javax.ws.rs.container.ContainerRequestContext;
|
||||
import javax.ws.rs.container.ContainerRequestFilter;
|
||||
import javax.ws.rs.container.ContainerResponseContext;
|
||||
import javax.ws.rs.container.ContainerResponseFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Priority(Priorities.USER)
|
||||
public class TraceRequestAndResponseFilter implements ContainerRequestFilter, ContainerResponseFilter {
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext) throws IOException {
|
||||
|
||||
requestContext.getHeaders().add("test-response", "header-result");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filter(
|
||||
ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext)
|
||||
throws IOException {
|
||||
|
||||
String headerString = containerRequestContext.getHeaderString("test-response");
|
||||
containerResponseContext.setEntity(headerString);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.intercept;
|
||||
|
||||
import javax.annotation.Priority;
|
||||
import javax.ws.rs.Priorities;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.ext.ReaderInterceptor;
|
||||
import javax.ws.rs.ext.ReaderInterceptorContext;
|
||||
import javax.ws.rs.ext.WriterInterceptor;
|
||||
import javax.ws.rs.ext.WriterInterceptorContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@Priority(Priorities.USER)
|
||||
public class DynamicTraceInterceptor implements ReaderInterceptor, WriterInterceptor {
|
||||
|
||||
public DynamicTraceInterceptor() {}
|
||||
|
||||
@Override
|
||||
public Object aroundReadFrom(ReaderInterceptorContext readerInterceptorContext)
|
||||
throws IOException, WebApplicationException {
|
||||
System.out.println("Dynamic reader interceptor invoked");
|
||||
return readerInterceptorContext.proceed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void aroundWriteTo(WriterInterceptorContext writerInterceptorContext)
|
||||
throws IOException, WebApplicationException {
|
||||
System.out.println("Dynamic writer interceptor invoked");
|
||||
writerInterceptorContext.getOutputStream().write("intercept".getBytes(StandardCharsets.UTF_8));
|
||||
writerInterceptorContext.proceed();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;
|
||||
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.User;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Path("u")
|
||||
@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
|
||||
public interface AnotherUserRestService {
|
||||
|
||||
@GET
|
||||
@Path("{id : \\d+}")
|
||||
@Produces({MediaType.APPLICATION_JSON})
|
||||
User getUser(@PathParam("id") Long id);
|
||||
|
||||
@POST
|
||||
@Path("register")
|
||||
@Produces("text/xml; charset=UTF-8")
|
||||
RegistrationResult registerUser(User user);
|
||||
|
||||
@GET
|
||||
@Path("context")
|
||||
@Produces({MediaType.TEXT_PLAIN})
|
||||
String getContext();
|
||||
|
||||
@POST
|
||||
@Path("bytes")
|
||||
@Produces({MediaType.APPLICATION_JSON})
|
||||
byte[] bytes(byte[] bytes);
|
||||
|
||||
@POST
|
||||
@Path("number")
|
||||
@Produces({MediaType.APPLICATION_JSON})
|
||||
Long number(Long number);
|
||||
|
||||
@POST
|
||||
@Path("headerMap")
|
||||
@Produces({MediaType.TEXT_PLAIN})
|
||||
String headerMap(@HeaderParam("headers") Map<String, String> headers);
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;
|
||||
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.User;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class AnotherUserRestServiceImpl implements AnotherUserRestService {
|
||||
|
||||
@Override
|
||||
public User getUser(Long id) {
|
||||
|
||||
User user = new User();
|
||||
user.setId(id);
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistrationResult registerUser(User user) {
|
||||
return new RegistrationResult(user.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContext() {
|
||||
|
||||
return "context";
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] bytes(byte[] bytes) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long number(Long number) {
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String headerMap(Map<String, String> headers) {
|
||||
return headers.get("headers");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HEAD;
|
||||
import javax.ws.rs.OPTIONS;
|
||||
import javax.ws.rs.PATCH;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.QueryParam;
|
||||
|
||||
@Path("/demoService")
|
||||
public interface HttpMethodService {
|
||||
|
||||
@POST
|
||||
@Path("/sayPost")
|
||||
@Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})
|
||||
String sayHelloPost(@QueryParam("name") String name);
|
||||
|
||||
@DELETE
|
||||
@Path("/sayDelete")
|
||||
@Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})
|
||||
String sayHelloDelete(@QueryParam("name") String name);
|
||||
|
||||
@HEAD
|
||||
@Path("/sayHead")
|
||||
@Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})
|
||||
String sayHelloHead();
|
||||
|
||||
@GET
|
||||
@Path("/sayGet")
|
||||
@Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})
|
||||
String sayHelloGet(@QueryParam("name") String name);
|
||||
|
||||
@PUT
|
||||
@Path("/sayPut")
|
||||
@Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})
|
||||
String sayHelloPut(@QueryParam("name") String name);
|
||||
|
||||
@PATCH
|
||||
@Path("/sayPatch")
|
||||
@Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})
|
||||
String sayHelloPatch(@QueryParam("name") String name);
|
||||
|
||||
@OPTIONS
|
||||
@Path("/sayOptions")
|
||||
@Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})
|
||||
String sayHelloOptions(@QueryParam("name") String name);
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;
|
||||
|
||||
public class HttpMethodServiceImpl implements HttpMethodService {
|
||||
|
||||
@Override
|
||||
public String sayHelloPost(String name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sayHelloDelete(String name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sayHelloHead() {
|
||||
return "hello";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sayHelloGet(String name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sayHelloPut(String name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sayHelloPatch(String name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sayHelloOptions(String name) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* DTO to customize the returned message
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class RegistrationResult implements Serializable {
|
||||
|
||||
private Long id;
|
||||
|
||||
public RegistrationResult() {}
|
||||
|
||||
public RegistrationResult(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
RegistrationResult that = (RegistrationResult) o;
|
||||
return Objects.equals(id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
@Path("/demoService")
|
||||
public interface RestDemoForTestException {
|
||||
|
||||
@POST
|
||||
@Path("/noFound")
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
String test404();
|
||||
|
||||
@GET
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
@Path("/hello")
|
||||
Integer test400(@QueryParam("a") String a, @QueryParam("b") String b);
|
||||
|
||||
@POST
|
||||
@Path("{uid}")
|
||||
String testMethodDisallowed(@PathParam("uid") String uid);
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.FormParam;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
@Path("/demoService")
|
||||
public interface RestDemoService {
|
||||
@GET
|
||||
@Path("/hello")
|
||||
Integer hello(@QueryParam("a") Integer a, @QueryParam("b") Integer b);
|
||||
|
||||
@GET
|
||||
@Path("/findUserById")
|
||||
Response findUserById(@QueryParam("id") Integer id);
|
||||
|
||||
@GET
|
||||
@Path("/error")
|
||||
String error();
|
||||
|
||||
@POST
|
||||
@Path("/say")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
String sayHello(String name);
|
||||
|
||||
@POST
|
||||
@Path("number")
|
||||
@Produces({MediaType.APPLICATION_FORM_URLENCODED})
|
||||
@Consumes({MediaType.APPLICATION_FORM_URLENCODED})
|
||||
Long testFormBody(@FormParam("number") Long number);
|
||||
|
||||
boolean isCalled();
|
||||
|
||||
@DELETE
|
||||
@Path("{uid}")
|
||||
String deleteUserByUid(@PathParam("uid") String uid);
|
||||
|
||||
@DELETE
|
||||
@Path("/deleteUserById/{uid}")
|
||||
public Response deleteUserById(@PathParam("uid") String uid);
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs.compatible.rest;
|
||||
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.resteasy.specimpl.BuiltResponse;
|
||||
|
||||
public class RestDemoServiceImpl implements RestDemoService {
|
||||
private static Map<String, Object> context;
|
||||
private boolean called;
|
||||
|
||||
@Override
|
||||
public String sayHello(String name) {
|
||||
called = true;
|
||||
return "Hello, " + name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long testFormBody(Long number) {
|
||||
return number;
|
||||
}
|
||||
|
||||
public boolean isCalled() {
|
||||
return called;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deleteUserByUid(String uid) {
|
||||
return uid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer hello(Integer a, Integer b) {
|
||||
context = RpcContext.getServerAttachment().getObjectAttachments();
|
||||
return a + b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response findUserById(Integer id) {
|
||||
Map<String, Object> content = new HashMap<>();
|
||||
content.put("username", "jack");
|
||||
content.put("id", id);
|
||||
|
||||
return BuiltResponse.ok(content).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String error() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response deleteUserById(String uid) {
|
||||
return Response.status(300).entity("deleted").build();
|
||||
}
|
||||
|
||||
public static Map<String, Object> getAttachments() {
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="org.apache.dubbo.rpc.protocol.tri.stream.StreamUtils" level="error"/>
|
||||
<Root level="info">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Root>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-plugin</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>dubbo-rest-servlet</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-triple</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-netty4</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
|
||||
|
||||
import org.apache.dubbo.common.config.Configuration;
|
||||
import org.apache.dubbo.common.config.ConfigurationUtils;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
|
||||
final class DummyFilterConfig implements FilterConfig {
|
||||
|
||||
private final String filterName;
|
||||
private final FrameworkModel frameworkModel;
|
||||
private final ServletContext servletContext;
|
||||
|
||||
public DummyFilterConfig(String filterName, FrameworkModel frameworkModel, ServletContext servletContext) {
|
||||
this.filterName = filterName;
|
||||
this.frameworkModel = frameworkModel;
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilterName() {
|
||||
return filterName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitParameter(String name) {
|
||||
String prefix = RestConstants.CONFIG_PREFIX + "filter-config.";
|
||||
Configuration conf = ConfigurationUtils.getGlobalConfiguration(frameworkModel.defaultApplication());
|
||||
String value = conf.getString(prefix + filterName + "." + name);
|
||||
if (value == null) {
|
||||
value = conf.getString(prefix + name);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getInitParameterNames() {
|
||||
return Collections.emptyEnumeration();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
|
||||
|
||||
import org.apache.dubbo.common.config.Configuration;
|
||||
import org.apache.dubbo.common.config.ConfigurationUtils;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterRegistration;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRegistration;
|
||||
import javax.servlet.SessionCookieConfig;
|
||||
import javax.servlet.SessionTrackingMode;
|
||||
import javax.servlet.descriptor.JspConfigDescriptor;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.EventListener;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
final class DummyServletContext implements ServletContext {
|
||||
|
||||
private final FrameworkModel frameworkModel;
|
||||
private final Map<String, Object> attributes = new HashMap<>();
|
||||
private final Map<String, String> initParameters = new HashMap<>();
|
||||
|
||||
public DummyServletContext(FrameworkModel frameworkModel) {
|
||||
this.frameworkModel = frameworkModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextPath() {
|
||||
return "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletContext getContext(String uripath) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMajorVersion() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinorVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEffectiveMajorVersion() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEffectiveMinorVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMimeType(String file) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getResourcePaths(String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getResource(String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestDispatcher getRequestDispatcher(String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestDispatcher getNamedDispatcher(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Servlet getServlet(String name) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<Servlet> getServlets() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getServletNames() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String msg) {
|
||||
LoggerFactory.getLogger(DummyServletContext.class).info(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Exception exception, String msg) {
|
||||
LoggerFactory.getLogger(DummyServletContext.class).info(msg, exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String message, Throwable throwable) {
|
||||
LoggerFactory.getLogger(DummyServletContext.class).info(message, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRealPath(String path) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerInfo() {
|
||||
return "Dubbo Rest Server/1.0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitParameter(String name) {
|
||||
String value = initParameters.get(name);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
Configuration conf = ConfigurationUtils.getGlobalConfiguration(frameworkModel.defaultApplication());
|
||||
return conf.getString(RestConstants.CONFIG_PREFIX + "servlet-context." + name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getInitParameterNames() {
|
||||
return Collections.enumeration(initParameters.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setInitParameter(String name, String value) {
|
||||
return initParameters.putIfAbsent(name, value) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name) {
|
||||
return attributes.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getAttributeNames() {
|
||||
return Collections.enumeration(attributes.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, Object object) {
|
||||
attributes.put(name, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
attributes.remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServletContextName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletRegistration.Dynamic addServlet(String servletName, String className) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Servlet> T createServlet(Class<T> clazz) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletRegistration getServletRegistration(String servletName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends ServletRegistration> getServletRegistrations() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterRegistration.Dynamic addFilter(String filterName, String className) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Filter> T createFilter(Class<T> clazz) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterRegistration getFilterRegistration(String filterName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionCookieConfig getSessionCookieConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(String className) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends EventListener> void addListener(T t) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(Class<? extends EventListener> listenerClass) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends EventListener> T createListener(Class<T> clazz) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JspConfigDescriptor getJspConfigDescriptor() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return getClass().getClassLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void declareRoles(String... roleNames) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVirtualServerName() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestException;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RestUtils;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Activate(onClass = "javax.servlet.Filter")
|
||||
public final class FilterAdapter implements RestExtensionAdapter<Filter> {
|
||||
|
||||
private final ServletHttpMessageAdapterFactory adapterFactory;
|
||||
|
||||
public FilterAdapter(FrameworkModel frameworkModel) {
|
||||
adapterFactory = (ServletHttpMessageAdapterFactory)
|
||||
frameworkModel.getExtension(HttpMessageAdapterFactory.class, "servlet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(Object extension) {
|
||||
return extension instanceof Filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestFilter adapt(Filter extension) {
|
||||
try {
|
||||
String filterName = extension.getClass().getSimpleName();
|
||||
extension.init(adapterFactory.adaptFilterConfig(filterName));
|
||||
} catch (ServletException e) {
|
||||
throw new RestException(e);
|
||||
}
|
||||
return new FilterRestFilter(extension);
|
||||
}
|
||||
|
||||
private static final class FilterRestFilter implements RestFilter {
|
||||
|
||||
private final Filter filter;
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return RestUtils.getPriority(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPatterns() {
|
||||
return RestUtils.getPattens(filter);
|
||||
}
|
||||
|
||||
public FilterRestFilter(Filter filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpRequest request, HttpResponse response, FilterChain chain) throws Exception {
|
||||
filter.doFilter((ServletRequest) request, (ServletResponse) response, (q, p) -> {
|
||||
try {
|
||||
chain.doFilter(request, response);
|
||||
} catch (RuntimeException | IOException | ServletException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new ServletException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("RestFilter{filter=");
|
||||
sb.append(filter);
|
||||
int priority = getPriority();
|
||||
if (priority != 0) {
|
||||
sb.append(", priority=").append(priority);
|
||||
}
|
||||
String[] patterns = getPatterns();
|
||||
if (patterns != null) {
|
||||
sb.append(", patterns=").append(Arrays.toString(patterns));
|
||||
}
|
||||
return sb.append('}').toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
|
||||
|
||||
import org.apache.dubbo.common.io.StreamUtils;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.remoting.http12.HttpCookie;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest.FileUpload;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestException;
|
||||
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
final class Helper {
|
||||
|
||||
private Helper() {}
|
||||
|
||||
static javax.servlet.http.Cookie[] convertCookies(Collection<HttpCookie> hCookies) {
|
||||
javax.servlet.http.Cookie[] cookies = new javax.servlet.http.Cookie[hCookies.size()];
|
||||
int i = 0;
|
||||
for (HttpCookie cookie : hCookies) {
|
||||
cookies[i++] = convert(cookie);
|
||||
}
|
||||
return cookies;
|
||||
}
|
||||
|
||||
static javax.servlet.http.Cookie convert(HttpCookie hCookie) {
|
||||
javax.servlet.http.Cookie cookie = new javax.servlet.http.Cookie(hCookie.name(), hCookie.value());
|
||||
if (hCookie.domain() != null) {
|
||||
cookie.setDomain(hCookie.domain());
|
||||
}
|
||||
cookie.setMaxAge((int) hCookie.maxAge());
|
||||
cookie.setHttpOnly(hCookie.httpOnly());
|
||||
cookie.setPath(hCookie.path());
|
||||
cookie.setSecure(hCookie.secure());
|
||||
return cookie;
|
||||
}
|
||||
|
||||
static HttpCookie convert(javax.servlet.http.Cookie sCookie) {
|
||||
HttpCookie cookie = new HttpCookie(sCookie.getName(), sCookie.getValue());
|
||||
cookie.setDomain(sCookie.getDomain());
|
||||
cookie.setMaxAge(sCookie.getMaxAge());
|
||||
cookie.setHttpOnly(sCookie.isHttpOnly());
|
||||
cookie.setPath(sCookie.getPath());
|
||||
cookie.setSecure(sCookie.getSecure());
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public static Part convert(FileUpload part) {
|
||||
return new FileUploadPart(part);
|
||||
}
|
||||
|
||||
public static Collection<Part> convertParts(Collection<FileUpload> parts) {
|
||||
if (CollectionUtils.isEmpty(parts)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Part> result = new ArrayList<>(parts.size());
|
||||
for (FileUpload part : parts) {
|
||||
result.add(convert(part));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final class FileUploadPart implements Part {
|
||||
|
||||
private final FileUpload fileUpload;
|
||||
|
||||
public FileUploadPart(FileUpload fileUpload) {
|
||||
this.fileUpload = fileUpload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return fileUpload.inputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return fileUpload.contentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return fileUpload.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubmittedFileName() {
|
||||
return fileUpload.filename();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
return fileUpload.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(String fileName) {
|
||||
try (FileOutputStream fos = new FileOutputStream(fileName)) {
|
||||
StreamUtils.copy(fileUpload.inputStream(), fos);
|
||||
} catch (IOException e) {
|
||||
throw new RestException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {}
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getHeaders(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getHeaderNames() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
|
||||
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
public interface HttpSessionFactory extends RestExtension {
|
||||
|
||||
HttpSession getSession(HttpServletRequest request, boolean create);
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestException;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Activate(onClass = "javax.servlet.http.HttpServletRequest")
|
||||
public class ServletArgumentResolver implements ArgumentResolver {
|
||||
|
||||
private static final Set<Class<?>> SUPPORTED_TYPES = new HashSet<>();
|
||||
|
||||
static {
|
||||
SUPPORTED_TYPES.add(ServletRequest.class);
|
||||
SUPPORTED_TYPES.add(HttpServletRequest.class);
|
||||
SUPPORTED_TYPES.add(ServletResponse.class);
|
||||
SUPPORTED_TYPES.add(HttpServletResponse.class);
|
||||
SUPPORTED_TYPES.add(HttpSession.class);
|
||||
SUPPORTED_TYPES.add(Cookie.class);
|
||||
SUPPORTED_TYPES.add(Cookie[].class);
|
||||
SUPPORTED_TYPES.add(Reader.class);
|
||||
SUPPORTED_TYPES.add(Writer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(ParameterMeta parameter) {
|
||||
return SUPPORTED_TYPES.contains(parameter.getActualType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolve(ParameterMeta parameter, HttpRequest request, HttpResponse response) {
|
||||
Class<?> type = parameter.getActualType();
|
||||
if (type == ServletRequest.class || type == HttpServletRequest.class) {
|
||||
return request;
|
||||
}
|
||||
if (type == ServletResponse.class || type == HttpServletResponse.class) {
|
||||
return response;
|
||||
}
|
||||
if (type == HttpSession.class) {
|
||||
return ((HttpServletRequest) request).getSession();
|
||||
}
|
||||
if (type == Cookie.class) {
|
||||
return Helper.convert(request.cookie(parameter.getRequiredName()));
|
||||
}
|
||||
if (type == Cookie[].class) {
|
||||
return ((HttpServletRequest) request).getCookies();
|
||||
}
|
||||
if (type == Reader.class) {
|
||||
try {
|
||||
return ((HttpServletRequest) request).getReader();
|
||||
} catch (IOException e) {
|
||||
throw new RestException(e);
|
||||
}
|
||||
}
|
||||
if (type == Writer.class) {
|
||||
try {
|
||||
return ((HttpServletResponse) response).getWriter();
|
||||
} catch (IOException e) {
|
||||
throw new RestException(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.http12.HttpChannel;
|
||||
import org.apache.dubbo.remoting.http12.HttpMetadata;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
@Activate(order = -100, onClass = "javax.servlet.http.HttpServletRequest")
|
||||
public final class ServletHttpMessageAdapterFactory
|
||||
implements HttpMessageAdapterFactory<ServletHttpRequestAdaptee, HttpMetadata, Void> {
|
||||
|
||||
private final FrameworkModel frameworkModel;
|
||||
private final ServletContext servletContext;
|
||||
private final HttpSessionFactory httpSessionFactory;
|
||||
|
||||
public ServletHttpMessageAdapterFactory(FrameworkModel frameworkModel) {
|
||||
this.frameworkModel = frameworkModel;
|
||||
servletContext = new DummyServletContext(frameworkModel);
|
||||
httpSessionFactory = getHttpSessionFactory(frameworkModel);
|
||||
}
|
||||
|
||||
private HttpSessionFactory getHttpSessionFactory(FrameworkModel frameworkModel) {
|
||||
for (RestExtension extension : frameworkModel.getActivateExtensions(RestExtension.class)) {
|
||||
if (extension instanceof HttpSessionFactory) {
|
||||
return (HttpSessionFactory) extension;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletHttpRequestAdaptee adaptRequest(HttpMetadata rawRequest, HttpChannel channel) {
|
||||
return new ServletHttpRequestAdaptee(rawRequest, channel, servletContext, httpSessionFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse adaptResponse(ServletHttpRequestAdaptee request, HttpMetadata rawRequest, Void rawResponse) {
|
||||
return new ServletHttpResponseAdaptee();
|
||||
}
|
||||
|
||||
public FilterConfig adaptFilterConfig(String filterName) {
|
||||
return new DummyFilterConfig(filterName, frameworkModel, servletContext);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,491 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
|
||||
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.remoting.http12.HttpChannel;
|
||||
import org.apache.dubbo.remoting.http12.HttpMetadata;
|
||||
import org.apache.dubbo.remoting.http12.message.DefaultHttpRequest;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpUpgradeHandler;
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.security.Principal;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class ServletHttpRequestAdaptee extends DefaultHttpRequest implements HttpServletRequest {
|
||||
|
||||
private final ServletContext servletContext;
|
||||
private final HttpSessionFactory sessionFactory;
|
||||
|
||||
private ServletInputStream sis;
|
||||
private BufferedReader reader;
|
||||
|
||||
public ServletHttpRequestAdaptee(
|
||||
HttpMetadata metadata,
|
||||
HttpChannel channel,
|
||||
ServletContext servletContext,
|
||||
HttpSessionFactory sessionFactory) {
|
||||
super(metadata, channel);
|
||||
this.servletContext = servletContext;
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthType() {
|
||||
return header("www-authenticate");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cookie[] getCookies() {
|
||||
return Helper.convertCookies(cookies());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDateHeader(String name) {
|
||||
Date date = dateHeader(name);
|
||||
return date == null ? -1L : date.getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
return header(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getHeaders(String name) {
|
||||
return Collections.enumeration(headerValues(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getHeaderNames() {
|
||||
return Collections.enumeration(headerNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntHeader(String name) {
|
||||
String headerValue = getHeader(name);
|
||||
try {
|
||||
return Integer.parseInt(headerValue);
|
||||
} catch (NumberFormatException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return method();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathTranslated() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextPath() {
|
||||
return "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryString() {
|
||||
return query();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteUser() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInRole(String role) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getUserPrincipal() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestedSessionId() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRequestURI() {
|
||||
return path();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuffer getRequestURL() {
|
||||
StringBuffer url = new StringBuffer(32);
|
||||
String scheme = getScheme();
|
||||
int port = getServerPort();
|
||||
url.append(scheme).append("://").append(getServerName());
|
||||
if (("http".equals(scheme) && port != 80) || ("https".equals(scheme) && port != 443)) {
|
||||
url.append(':');
|
||||
url.append(port);
|
||||
}
|
||||
url.append(path());
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServletPath() {
|
||||
return path();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSession getSession(boolean create) {
|
||||
if (sessionFactory == null) {
|
||||
throw new UnsupportedOperationException("No HttpSessionFactory found");
|
||||
}
|
||||
return sessionFactory.getSession(this, create);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpSession getSession() {
|
||||
return getSession(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String changeSessionId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequestedSessionIdValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequestedSessionIdFromCookie() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequestedSessionIdFromURL() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequestedSessionIdFromUrl() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean authenticate(HttpServletResponse response) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void login(String username, String password) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Part> getParts() {
|
||||
return Helper.convertParts(parts());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Part getPart(String name) {
|
||||
return Helper.convert(part(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name) {
|
||||
return attribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getAttributeNames() {
|
||||
return Collections.enumeration(attributeNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterEncoding() {
|
||||
return charset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterEncoding(String env) {
|
||||
setCharset(env);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentLength() {
|
||||
return contentLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getContentLengthLong() {
|
||||
return contentLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return contentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() {
|
||||
if (sis == null) {
|
||||
sis = new HttpInputStream(inputStream());
|
||||
}
|
||||
return sis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter(String name) {
|
||||
return parameter(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getParameterNames() {
|
||||
return Collections.enumeration(parameterNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameterValues(String name) {
|
||||
List<String> values = parameterValues(name);
|
||||
return values == null ? null : values.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String[]> getParameterMap() {
|
||||
Collection<String> paramNames = parameterNames();
|
||||
if (paramNames.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, String[]> result = CollectionUtils.newLinkedHashMap(paramNames.size());
|
||||
for (String paramName : paramNames) {
|
||||
result.put(paramName, getParameterValues(paramName));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return isHttp2() ? "HTTP/2.0" : "HTTP/1.1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return scheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerName() {
|
||||
return serverName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getServerPort() {
|
||||
return serverPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedReader getReader() {
|
||||
if (reader == null) {
|
||||
reader = new BufferedReader(new InputStreamReader(inputStream(), charsetOrDefault()));
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteAddr() {
|
||||
return remoteAddr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteHost() {
|
||||
return String.valueOf(remotePort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return locale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<Locale> getLocales() {
|
||||
return Collections.enumeration(locales());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return "https".equals(scheme());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestDispatcher getRequestDispatcher(String path) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRealPath(String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRemotePort() {
|
||||
return remotePort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalName() {
|
||||
return localHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalAddr() {
|
||||
return localAddr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalPort() {
|
||||
return localPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncContext startAsync() throws IllegalStateException {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
|
||||
throws IllegalStateException {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAsyncStarted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAsyncSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncContext getAsyncContext() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DispatcherType getDispatcherType() {
|
||||
return DispatcherType.REQUEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServletHttpRequestAdaptee{" + fieldToString() + '}';
|
||||
}
|
||||
|
||||
private static final class HttpInputStream extends ServletInputStream {
|
||||
|
||||
private final InputStream is;
|
||||
|
||||
HttpInputStream(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return is.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
return is.read(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
is.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readLine(byte[] b, int off, int len) throws IOException {
|
||||
return is.read(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
try {
|
||||
return is.available() == 0;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
|
||||
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.remoting.http12.HttpUtils;
|
||||
import org.apache.dubbo.remoting.http12.message.DefaultHttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.WriteListener;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ServletHttpResponseAdaptee extends DefaultHttpResponse implements HttpServletResponse {
|
||||
|
||||
private ServletOutputStream sos;
|
||||
private PrintWriter writer;
|
||||
|
||||
@Override
|
||||
public void addCookie(Cookie cookie) {
|
||||
addCookie(Helper.convert(cookie));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsHeader(String name) {
|
||||
return hasHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeURL(String url) {
|
||||
return RequestUtils.encodeURL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeRedirectURL(String url) {
|
||||
return RequestUtils.encodeURL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeUrl(String url) {
|
||||
return RequestUtils.encodeURL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeRedirectUrl(String url) {
|
||||
return RequestUtils.encodeURL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDateHeader(String name, long date) {
|
||||
setHeader(name, new Date(date));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDateHeader(String name, long date) {
|
||||
addHeader(name, new Date(date));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntHeader(String name, int value) {
|
||||
setHeader(name, String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIntHeader(String name, int value) {
|
||||
addHeader(name, String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(int sc, String sm) {
|
||||
setStatus(sc);
|
||||
setBody(sm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus() {
|
||||
return status();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
return header(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getHeaders(String name) {
|
||||
return headerValues(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getHeaderNames() {
|
||||
return headerNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterEncoding() {
|
||||
return charset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return contentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletOutputStream getOutputStream() {
|
||||
if (sos == null) {
|
||||
sos = new HttpOutputStream(outputStream());
|
||||
}
|
||||
return sos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getWriter() {
|
||||
if (writer == null) {
|
||||
writer = new PrintWriter(getOutputStream());
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterEncoding(String charset) {
|
||||
setCharset(charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(int len) {}
|
||||
|
||||
@Override
|
||||
public void setContentLengthLong(long len) {}
|
||||
|
||||
@Override
|
||||
public void setBufferSize(int size) {}
|
||||
|
||||
@Override
|
||||
public int getBufferSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushBuffer() throws IOException {
|
||||
//noinspection resource
|
||||
OutputStream os = outputStream();
|
||||
if (os instanceof BufferedOutputStream) {
|
||||
os.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocale(Locale loc) {
|
||||
setLocale(loc.toLanguageTag());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
Locale locale = CollectionUtils.first(HttpUtils.parseContentLanguage(locale()));
|
||||
return locale == null ? Locale.getDefault() : locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServletHttpResponseAdaptee{" + fieldToString() + '}';
|
||||
}
|
||||
|
||||
private static final class HttpOutputStream extends ServletOutputStream {
|
||||
|
||||
private final OutputStream outputStream;
|
||||
|
||||
private HttpOutputStream(OutputStream outputStream) {
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
outputStream.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
outputStream.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
outputStream.write(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWriteListener(WriteListener writeListener) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
servlet=org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.ServletHttpMessageAdapterFactory
|
||||
|
|
@ -0,0 +1 @@
|
|||
servlet=org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.ServletArgumentResolver
|
||||
|
|
@ -0,0 +1 @@
|
|||
servlet-filter=org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.FilterAdapter
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<Configuration status="WARN">
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT" follow="true">
|
||||
<PatternLayout pattern="%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] %40.40c:%-3L -| %m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}" charset="UTF-8"/>
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="org.apache.dubbo.rpc.protocol.tri.stream.StreamUtils" level="error"/>
|
||||
<Root level="info">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-plugin</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>dubbo-rest-spring</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-triple</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-config-spring</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rest-servlet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-remoting-netty4</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-rest</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-jaxrs</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-client</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.spring;
|
||||
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractAnnotationBaseArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public abstract class AbstractSpringArgumentResolver extends AbstractAnnotationBaseArgumentResolver {
|
||||
|
||||
@Override
|
||||
protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta<Annotation> ann) {
|
||||
return new NamedValueMeta(ann.getValue(), Helper.isRequired(ann), Helper.defaultValue(ann));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.spring;
|
||||
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationEnum;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public enum Annotations implements AnnotationEnum {
|
||||
RequestMapping,
|
||||
PathVariable,
|
||||
MatrixVariable,
|
||||
RequestParam,
|
||||
RequestHeader,
|
||||
CookieValue,
|
||||
RequestAttribute,
|
||||
RequestPart,
|
||||
RequestBody,
|
||||
ModelAttribute,
|
||||
ResponseStatus,
|
||||
CrossOrigin,
|
||||
ExceptionHandler,
|
||||
Nonnull("javax.annotation.Nonnull");
|
||||
|
||||
private final String className;
|
||||
private Class<Annotation> type;
|
||||
|
||||
Annotations() {
|
||||
className = "org.springframework.web.bind.annotation." + name();
|
||||
}
|
||||
|
||||
Annotations(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String className() {
|
||||
return className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Annotation> type() {
|
||||
if (type == null) {
|
||||
type = loadType();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.spring;
|
||||
|
||||
import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.Messages;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.RestException;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.DataBinder;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
|
||||
final class BeanArgumentBinder {
|
||||
|
||||
private final ArgumentResolver argumentResolver;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
private final Map<Class<?>, ConstructorMeta> cache = CollectionUtils.newConcurrentHashMap();
|
||||
|
||||
BeanArgumentBinder(FrameworkModel frameworkModel, ConversionService conversionService) {
|
||||
ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();
|
||||
argumentResolver = beanFactory.getOrRegisterBean(CompositeArgumentResolver.class);
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response) {
|
||||
String name = StringUtils.defaultIf(parameter.getName(), DataBinder.DEFAULT_OBJECT_NAME);
|
||||
try {
|
||||
Object bean = buildBean(parameter, request, response);
|
||||
WebDataBinder binder = new WebDataBinder(bean, name);
|
||||
binder.setConversionService(conversionService);
|
||||
binder.bind(new MutablePropertyValues(RequestUtils.getParametersMap(request)));
|
||||
BindingResult result = binder.getBindingResult();
|
||||
if (result.hasErrors()) {
|
||||
throw new BindException(result);
|
||||
}
|
||||
return binder.getTarget();
|
||||
} catch (Exception e) {
|
||||
throw new RestException(e, Messages.ARGUMENT_BIND_ERROR, name, parameter.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private Object buildBean(ParameterMeta parameter, HttpRequest request, HttpResponse response) throws Exception {
|
||||
Class<?> type = parameter.getActualType();
|
||||
if (Modifier.isAbstract(type.getModifiers())) {
|
||||
throw new IllegalStateException(Messages.ARGUMENT_COULD_NOT_RESOLVED.format(parameter.getDescription()));
|
||||
}
|
||||
ConstructorMeta ct = cache.computeIfAbsent(type, k -> resolveConstructor(parameter.getToolKit(), k));
|
||||
ParameterMeta[] parameters = ct.parameters;
|
||||
int len = parameters.length;
|
||||
Object[] args = new Object[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
args[i] = argumentResolver.resolve(parameters[i], request, response);
|
||||
}
|
||||
return ct.newInstance(args);
|
||||
}
|
||||
|
||||
private ConstructorMeta resolveConstructor(RestToolKit toolKit, Class<?> type) {
|
||||
Constructor<?>[] constructors = type.getConstructors();
|
||||
Constructor<?> ct = null;
|
||||
if (constructors.length == 1) {
|
||||
ct = constructors[0];
|
||||
} else {
|
||||
try {
|
||||
ct = type.getDeclaredConstructor();
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
}
|
||||
if (ct == null) {
|
||||
throw new IllegalArgumentException("No available default constructor found in " + type);
|
||||
}
|
||||
return new ConstructorMeta(toolKit, ct);
|
||||
}
|
||||
|
||||
private static final class ConstructorMeta {
|
||||
|
||||
private final Constructor<?> constructor;
|
||||
private final ConstructorParameterMeta[] parameters;
|
||||
|
||||
ConstructorMeta(RestToolKit toolKit, Constructor<?> constructor) {
|
||||
this.constructor = constructor;
|
||||
parameters = initParameters(toolKit, constructor);
|
||||
}
|
||||
|
||||
private ConstructorParameterMeta[] initParameters(RestToolKit toolKit, Constructor<?> ct) {
|
||||
Parameter[] cps = ct.getParameters();
|
||||
int len = cps.length;
|
||||
ConstructorParameterMeta[] parameters = new ConstructorParameterMeta[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
parameters[i] = new ConstructorParameterMeta(toolKit, cps[i]);
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
Object newInstance(Object[] args) throws Exception {
|
||||
return constructor.newInstance(args);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ConstructorParameterMeta extends ParameterMeta {
|
||||
|
||||
private final Parameter parameter;
|
||||
|
||||
ConstructorParameterMeta(RestToolKit toolKit, Parameter parameter) {
|
||||
super(toolKit, parameter.isNamePresent() ? parameter.getName() : null);
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotatedElement getAnnotatedElement() {
|
||||
return parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
return parameter.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getGenericType() {
|
||||
return parameter.getParameterizedType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.spring;
|
||||
|
||||
import org.apache.dubbo.common.config.Configuration;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public final class ConfigurationWrapper extends Properties {
|
||||
|
||||
private final Configuration configuration;
|
||||
|
||||
ConfigurationWrapper(ApplicationModel applicationModel) {
|
||||
configuration = applicationModel.modelEnvironment().getConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key) {
|
||||
Object value = configuration.getProperty(key);
|
||||
return value == null ? null : value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return configuration.getProperty(key == null ? null : key.toString());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.protocol.tri.rest.support.spring;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.remoting.http12.HttpCookie;
|
||||
import org.apache.dubbo.remoting.http12.HttpRequest;
|
||||
import org.apache.dubbo.remoting.http12.HttpResponse;
|
||||
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Activate(onClass = "org.springframework.web.bind.annotation.CookieValue")
|
||||
public class CookieValueArgumentResolver extends AbstractSpringArgumentResolver {
|
||||
|
||||
@Override
|
||||
public Class<Annotation> accept() {
|
||||
return Annotations.CookieValue.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
return request.cookie(meta.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
Collection<HttpCookie> cookies = request.cookies();
|
||||
if (cookies.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String name = meta.name();
|
||||
List<HttpCookie> result = new ArrayList<>(cookies.size());
|
||||
for (HttpCookie cookie : cookies) {
|
||||
if (name.equals(cookie.name())) {
|
||||
result.add(cookie);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) {
|
||||
Collection<HttpCookie> cookies = request.cookies();
|
||||
if (cookies.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, List<HttpCookie>> mapValue = CollectionUtils.newLinkedHashMap(cookies.size());
|
||||
for (HttpCookie cookie : cookies) {
|
||||
mapValue.computeIfAbsent(cookie.name(), k -> new ArrayList<>()).add(cookie);
|
||||
}
|
||||
return mapValue;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue