Merge pull request from #1001, merge dubbox branch
1. rest protocol 2. kryo & fst serialization 3. embed tomcat
This commit is contained in:
parent
72cecba20b
commit
ab8af672e6
|
|
@ -57,6 +57,18 @@ limitations under the License.
|
|||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.esotericsoftware.kryo</groupId>
|
||||
<artifactId>kryo</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.javakaffee</groupId>
|
||||
<artifactId>kryo-serializers</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.ruedigermoeller</groupId>
|
||||
<artifactId>fst</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jvnet.sorcerer</groupId>
|
||||
<artifactId>sorcerer-javac</artifactId>
|
||||
|
|
|
|||
|
|
@ -259,6 +259,12 @@ public class Constants {
|
|||
|
||||
public static final String SERIALIZATION_KEY = "serialization";
|
||||
|
||||
public static final String EXTENSION_KEY = "extension";
|
||||
|
||||
public static final String KEEP_ALIVE_KEY = "keepalive";
|
||||
|
||||
public static final String OPTIMIZER_KEY = "optimizer";
|
||||
|
||||
public static final String EXCHANGER_KEY = "exchanger";
|
||||
|
||||
public static final String TRANSPORTER_KEY = "transporter";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public interface Cleanable {
|
||||
|
||||
void cleanup();
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize;
|
||||
|
||||
/**
|
||||
* Just a marker interface for now
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
public interface OptimizedSerialization extends Serialization {
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.alibaba.dubbo.common.serialize.support;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public abstract class SerializableClassRegistry {
|
||||
|
||||
private static final Set<Class> registrations = new LinkedHashSet<Class>();
|
||||
|
||||
/**
|
||||
* only supposed to be called at startup time
|
||||
*/
|
||||
public static void registerClass(Class clazz) {
|
||||
registrations.add(clazz);
|
||||
}
|
||||
|
||||
public static Set<Class> getRegisteredClasses() {
|
||||
return registrations;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.alibaba.dubbo.common.serialize.support;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* This class can be replaced with the contents in config file, but for now I think the class is easier to write
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
public interface SerializationOptimizer {
|
||||
|
||||
Collection<Class> getSerializableClasses();
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.fst;
|
||||
|
||||
import com.alibaba.dubbo.common.serialize.support.SerializableClassRegistry;
|
||||
import de.ruedigermoeller.serialization.FSTConfiguration;
|
||||
import de.ruedigermoeller.serialization.FSTObjectInput;
|
||||
import de.ruedigermoeller.serialization.FSTObjectOutput;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class FstFactory {
|
||||
|
||||
private static final FstFactory factory = new FstFactory();
|
||||
|
||||
private final FSTConfiguration conf = FSTConfiguration.createDefaultConfiguration();
|
||||
|
||||
|
||||
public static FstFactory getDefaultFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
public FstFactory() {
|
||||
for (Class clazz : SerializableClassRegistry.getRegisteredClasses()) {
|
||||
conf.registerClass(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public FSTObjectOutput getObjectOutput(OutputStream outputStream) {
|
||||
return conf.getObjectOutput(outputStream);
|
||||
}
|
||||
|
||||
public FSTObjectInput getObjectInput(InputStream inputStream) {
|
||||
return conf.getObjectInput(inputStream);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.fst;
|
||||
|
||||
import com.alibaba.dubbo.common.serialize.ObjectInput;
|
||||
import de.ruedigermoeller.serialization.FSTObjectInput;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class FstObjectInput implements ObjectInput {
|
||||
|
||||
private FSTObjectInput input;
|
||||
|
||||
public FstObjectInput(InputStream inputStream) {
|
||||
input = FstFactory.getDefaultFactory().getObjectInput(inputStream);
|
||||
}
|
||||
|
||||
public boolean readBool() throws IOException {
|
||||
return input.readBoolean();
|
||||
}
|
||||
|
||||
public byte readByte() throws IOException {
|
||||
return input.readByte();
|
||||
}
|
||||
|
||||
public short readShort() throws IOException {
|
||||
return input.readShort();
|
||||
}
|
||||
|
||||
public int readInt() throws IOException {
|
||||
return input.readInt();
|
||||
}
|
||||
|
||||
public long readLong() throws IOException {
|
||||
return input.readLong();
|
||||
}
|
||||
|
||||
public float readFloat() throws IOException {
|
||||
return input.readFloat();
|
||||
}
|
||||
|
||||
public double readDouble() throws IOException {
|
||||
return input.readDouble();
|
||||
}
|
||||
|
||||
public byte[] readBytes() throws IOException {
|
||||
int len = input.readInt();
|
||||
if (len < 0) {
|
||||
return null;
|
||||
} else if (len == 0) {
|
||||
return new byte[]{};
|
||||
} else {
|
||||
byte[] b = new byte[len];
|
||||
input.readFully(b);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
public String readUTF() throws IOException {
|
||||
return input.readUTF();
|
||||
}
|
||||
|
||||
public Object readObject() throws IOException, ClassNotFoundException {
|
||||
return input.readObject();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T readObject(Class<T> clazz) throws IOException, ClassNotFoundException {
|
||||
return (T) readObject();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T readObject(Class<T> clazz, Type type) throws IOException, ClassNotFoundException {
|
||||
return (T) readObject();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.fst;
|
||||
|
||||
import com.alibaba.dubbo.common.serialize.ObjectOutput;
|
||||
import de.ruedigermoeller.serialization.FSTObjectOutput;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class FstObjectOutput implements ObjectOutput {
|
||||
|
||||
private FSTObjectOutput output;
|
||||
|
||||
public FstObjectOutput(OutputStream outputStream) {
|
||||
output = FstFactory.getDefaultFactory().getObjectOutput(outputStream);
|
||||
}
|
||||
|
||||
public void writeBool(boolean v) throws IOException {
|
||||
output.writeBoolean(v);
|
||||
}
|
||||
|
||||
public void writeByte(byte v) throws IOException {
|
||||
output.writeByte(v);
|
||||
}
|
||||
|
||||
public void writeShort(short v) throws IOException {
|
||||
output.writeShort(v);
|
||||
}
|
||||
|
||||
public void writeInt(int v) throws IOException {
|
||||
output.writeInt(v);
|
||||
}
|
||||
|
||||
public void writeLong(long v) throws IOException {
|
||||
output.writeLong(v);
|
||||
}
|
||||
|
||||
public void writeFloat(float v) throws IOException {
|
||||
output.writeFloat(v);
|
||||
}
|
||||
|
||||
public void writeDouble(double v) throws IOException {
|
||||
output.writeDouble(v);
|
||||
}
|
||||
|
||||
public void writeBytes(byte[] v) throws IOException {
|
||||
if (v == null) {
|
||||
output.writeInt(-1);
|
||||
} else {
|
||||
writeBytes(v, 0, v.length);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeBytes(byte[] v, int off, int len) throws IOException {
|
||||
if (v == null) {
|
||||
output.writeInt(-1);
|
||||
} else {
|
||||
output.writeInt(len);
|
||||
output.write(v, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void writeUTF(String v) throws IOException {
|
||||
output.writeUTF(v);
|
||||
}
|
||||
|
||||
public void writeObject(Object v) throws IOException {
|
||||
output.writeObject(v);
|
||||
}
|
||||
|
||||
public void flushBuffer() throws IOException {
|
||||
output.flush();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.fst;
|
||||
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectInput;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectOutput;
|
||||
import com.alibaba.dubbo.common.serialize.OptimizedSerialization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class FstSerialization implements OptimizedSerialization {
|
||||
|
||||
public byte getContentTypeId() {
|
||||
return 9;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return "x-application/fst";
|
||||
}
|
||||
|
||||
public ObjectOutput serialize(URL url, OutputStream out) throws IOException {
|
||||
return new FstObjectOutput(out);
|
||||
}
|
||||
|
||||
public ObjectInput deserialize(URL url, InputStream is) throws IOException {
|
||||
return new FstObjectInput(is);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.kryo;
|
||||
|
||||
import com.alibaba.dubbo.common.logger.Logger;
|
||||
import com.alibaba.dubbo.common.logger.LoggerFactory;
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
import com.esotericsoftware.kryo.Serializer;
|
||||
import com.esotericsoftware.kryo.serializers.JavaSerializer;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class CompatibleKryo extends Kryo {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompatibleKryo.class);
|
||||
|
||||
@Override
|
||||
public Serializer getDefaultSerializer(Class type) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("type cannot be null.");
|
||||
}
|
||||
|
||||
if (!type.isArray() && !ReflectionUtils.checkZeroArgConstructor(type)) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(type + " has no zero-arg constructor and this will affect the serialization performance");
|
||||
}
|
||||
return new JavaSerializer();
|
||||
}
|
||||
return super.getDefaultSerializer(type);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.kryo;
|
||||
|
||||
import com.alibaba.dubbo.common.serialize.support.SerializableClassRegistry;
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
import com.esotericsoftware.kryo.serializers.DefaultSerializers;
|
||||
import de.javakaffee.kryoserializers.*;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URI;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public abstract class KryoFactory {
|
||||
|
||||
// private static final KryoFactory factory = new PrototypeKryoFactory();
|
||||
// private static final KryoFactory factory = new SingletonKryoFactory();
|
||||
private static final KryoFactory factory = new PooledKryoFactory();
|
||||
|
||||
private final Set<Class> registrations = new LinkedHashSet<Class>();
|
||||
|
||||
private boolean registrationRequired;
|
||||
|
||||
private volatile boolean kryoCreated;
|
||||
|
||||
protected KryoFactory() {
|
||||
// TODO configurable
|
||||
// Log.DEBUG();
|
||||
}
|
||||
|
||||
public static KryoFactory getDefaultFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* only supposed to be called at startup time
|
||||
*
|
||||
* later may consider adding support for custom serializer, custom id, etc
|
||||
*/
|
||||
public void registerClass(Class clazz) {
|
||||
|
||||
if (kryoCreated) {
|
||||
throw new IllegalStateException("Can't register class after creating kryo instance");
|
||||
}
|
||||
registrations.add(clazz);
|
||||
}
|
||||
|
||||
protected Kryo createKryo() {
|
||||
if (!kryoCreated) {
|
||||
kryoCreated = true;
|
||||
}
|
||||
|
||||
Kryo kryo = new CompatibleKryo();
|
||||
|
||||
// TODO
|
||||
// kryo.setReferences(false);
|
||||
kryo.setRegistrationRequired(registrationRequired);
|
||||
|
||||
kryo.register(Arrays.asList("").getClass(), new ArraysAsListSerializer());
|
||||
kryo.register(GregorianCalendar.class, new GregorianCalendarSerializer());
|
||||
kryo.register(InvocationHandler.class, new JdkProxySerializer());
|
||||
kryo.register(BigDecimal.class, new DefaultSerializers.BigDecimalSerializer());
|
||||
kryo.register(BigInteger.class, new DefaultSerializers.BigIntegerSerializer());
|
||||
kryo.register(Pattern.class, new RegexSerializer());
|
||||
kryo.register(BitSet.class, new BitSetSerializer());
|
||||
kryo.register(URI.class, new URISerializer());
|
||||
kryo.register(UUID.class, new UUIDSerializer());
|
||||
UnmodifiableCollectionsSerializer.registerSerializers(kryo);
|
||||
SynchronizedCollectionsSerializer.registerSerializers(kryo);
|
||||
|
||||
// now just added some very common classes
|
||||
// TODO optimization
|
||||
kryo.register(HashMap.class);
|
||||
kryo.register(ArrayList.class);
|
||||
kryo.register(LinkedList.class);
|
||||
kryo.register(HashSet.class);
|
||||
kryo.register(TreeSet.class);
|
||||
kryo.register(Hashtable.class);
|
||||
kryo.register(Date.class);
|
||||
kryo.register(Calendar.class);
|
||||
kryo.register(ConcurrentHashMap.class);
|
||||
kryo.register(SimpleDateFormat.class);
|
||||
kryo.register(GregorianCalendar.class);
|
||||
kryo.register(Vector.class);
|
||||
kryo.register(BitSet.class);
|
||||
kryo.register(StringBuffer.class);
|
||||
kryo.register(StringBuilder.class);
|
||||
kryo.register(Object.class);
|
||||
kryo.register(Object[].class);
|
||||
kryo.register(String[].class);
|
||||
kryo.register(byte[].class);
|
||||
kryo.register(char[].class);
|
||||
kryo.register(int[].class);
|
||||
kryo.register(float[].class);
|
||||
kryo.register(double[].class);
|
||||
|
||||
for (Class clazz : registrations) {
|
||||
kryo.register(clazz);
|
||||
}
|
||||
|
||||
for (Class clazz : SerializableClassRegistry.getRegisteredClasses()) {
|
||||
kryo.register(clazz);
|
||||
}
|
||||
|
||||
return kryo;
|
||||
}
|
||||
|
||||
public void returnKryo(Kryo kryo) {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
public void setRegistrationRequired(boolean registrationRequired) {
|
||||
this.registrationRequired = registrationRequired;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
public abstract Kryo getKryo();
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.kryo;
|
||||
|
||||
import com.alibaba.dubbo.common.serialize.Cleanable;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectInput;
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
import com.esotericsoftware.kryo.KryoException;
|
||||
import com.esotericsoftware.kryo.io.Input;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class KryoObjectInput implements ObjectInput, Cleanable {
|
||||
|
||||
private Kryo kryo = KryoFactory.getDefaultFactory().getKryo();
|
||||
private Input input;
|
||||
|
||||
public KryoObjectInput(InputStream inputStream) {
|
||||
input = new Input(inputStream);
|
||||
}
|
||||
|
||||
public boolean readBool() throws IOException {
|
||||
try {
|
||||
return input.readBoolean();
|
||||
} catch (KryoException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public byte readByte() throws IOException {
|
||||
try {
|
||||
return input.readByte();
|
||||
} catch (KryoException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public short readShort() throws IOException {
|
||||
try {
|
||||
return input.readShort();
|
||||
} catch (KryoException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int readInt() throws IOException {
|
||||
try {
|
||||
return input.readInt();
|
||||
} catch (KryoException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public long readLong() throws IOException {
|
||||
try {
|
||||
return input.readLong();
|
||||
} catch (KryoException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public float readFloat() throws IOException {
|
||||
try {
|
||||
return input.readFloat();
|
||||
} catch (KryoException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public double readDouble() throws IOException {
|
||||
try {
|
||||
return input.readDouble();
|
||||
} catch (KryoException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] readBytes() throws IOException {
|
||||
try {
|
||||
int len = input.readInt();
|
||||
if (len < 0) {
|
||||
return null;
|
||||
} else if (len == 0) {
|
||||
return new byte[]{};
|
||||
} else {
|
||||
return input.readBytes(len);
|
||||
}
|
||||
} catch (KryoException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String readUTF() throws IOException {
|
||||
// TODO
|
||||
try {
|
||||
// return kryo.readObject(input, String.class);
|
||||
return input.readString();
|
||||
} catch (KryoException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readObject() throws IOException, ClassNotFoundException {
|
||||
// TODO
|
||||
// throw new UnsupportedOperationException();
|
||||
try {
|
||||
return kryo.readClassAndObject(input);
|
||||
} catch (KryoException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T readObject(Class<T> clazz) throws IOException, ClassNotFoundException {
|
||||
// TODO optimization
|
||||
// try {
|
||||
// return (T) kryo.readClassAndObject(input);
|
||||
// } catch (KryoException e) {
|
||||
// throw new IOException(e);
|
||||
// }
|
||||
return (T) readObject();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T readObject(Class<T> clazz, Type type) throws IOException, ClassNotFoundException {
|
||||
// try {
|
||||
// return readObject(clazz);
|
||||
// } catch (KryoException e) {
|
||||
// throw new IOException(e);
|
||||
// }
|
||||
// TODO optimization
|
||||
return (T) readObject(clazz);
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
KryoFactory.getDefaultFactory().returnKryo(kryo);
|
||||
kryo = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.kryo;
|
||||
|
||||
import com.alibaba.dubbo.common.serialize.Cleanable;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectOutput;
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
import com.esotericsoftware.kryo.io.Output;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class KryoObjectOutput implements ObjectOutput, Cleanable {
|
||||
|
||||
private Kryo kryo = KryoFactory.getDefaultFactory().getKryo();
|
||||
private Output output;
|
||||
|
||||
public KryoObjectOutput(OutputStream outputStream) {
|
||||
output = new Output(outputStream);
|
||||
}
|
||||
|
||||
public void writeBool(boolean v) throws IOException {
|
||||
output.writeBoolean(v);
|
||||
}
|
||||
|
||||
public void writeByte(byte v) throws IOException {
|
||||
output.writeByte(v);
|
||||
}
|
||||
|
||||
public void writeShort(short v) throws IOException {
|
||||
output.writeShort(v);
|
||||
}
|
||||
|
||||
public void writeInt(int v) throws IOException {
|
||||
output.writeInt(v);
|
||||
}
|
||||
|
||||
public void writeLong(long v) throws IOException {
|
||||
output.writeLong(v);
|
||||
}
|
||||
|
||||
public void writeFloat(float v) throws IOException {
|
||||
output.writeFloat(v);
|
||||
}
|
||||
|
||||
public void writeDouble(double v) throws IOException {
|
||||
output.writeDouble(v);
|
||||
}
|
||||
|
||||
public void writeBytes(byte[] v) throws IOException {
|
||||
if (v == null) {
|
||||
output.writeInt(-1);
|
||||
} else {
|
||||
writeBytes(v, 0, v.length);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeBytes(byte[] v, int off, int len) throws IOException {
|
||||
if (v == null) {
|
||||
output.writeInt(-1);
|
||||
} else {
|
||||
output.writeInt(len);
|
||||
output.write(v, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void writeUTF(String v) throws IOException {
|
||||
// TODO
|
||||
output.writeString(v);
|
||||
// kryo.writeObject(output, v);
|
||||
}
|
||||
|
||||
public void writeObject(Object v) throws IOException {
|
||||
kryo.writeClassAndObject(output, v);
|
||||
}
|
||||
|
||||
public void flushBuffer() throws IOException {
|
||||
output.flush();
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
KryoFactory.getDefaultFactory().returnKryo(kryo);
|
||||
kryo = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.kryo;
|
||||
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectInput;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectOutput;
|
||||
import com.alibaba.dubbo.common.serialize.OptimizedSerialization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* TODO for now kryo serialization doesn't deny classes that don't implement the serializable interface
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
public class KryoSerialization implements OptimizedSerialization {
|
||||
|
||||
public byte getContentTypeId() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return "x-application/kryo";
|
||||
}
|
||||
|
||||
public ObjectOutput serialize(URL url, OutputStream out) throws IOException {
|
||||
return new KryoObjectOutput(out);
|
||||
}
|
||||
|
||||
public ObjectInput deserialize(URL url, InputStream is) throws IOException {
|
||||
return new KryoObjectInput(is);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.kryo;
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class PooledKryoFactory extends KryoFactory {
|
||||
|
||||
private final Queue<Kryo> pool = new ConcurrentLinkedQueue<Kryo>();
|
||||
|
||||
@Override
|
||||
public void returnKryo(Kryo kryo) {
|
||||
pool.offer(kryo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
pool.clear();
|
||||
}
|
||||
|
||||
public Kryo getKryo() {
|
||||
Kryo kryo = pool.poll();
|
||||
if (kryo == null) {
|
||||
kryo = createKryo();
|
||||
}
|
||||
return kryo;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.kryo;
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class PrototypeKryoFactory extends KryoFactory {
|
||||
|
||||
public Kryo getKryo() {
|
||||
return createKryo();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.kryo;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public abstract class ReflectionUtils {
|
||||
|
||||
public static boolean checkZeroArgConstructor(Class clazz) {
|
||||
try {
|
||||
clazz.getDeclaredConstructor();
|
||||
return true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.kryo;
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
|
||||
/**
|
||||
* CAUSION this is only for test purpose since both kryo and this class are not thread-safe
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
public class SingletonKryoFactory extends KryoFactory {
|
||||
|
||||
// private final Kryo instance = createKryo();
|
||||
private Kryo instance;
|
||||
|
||||
@Override
|
||||
public Kryo getKryo() {
|
||||
if (instance == null) {
|
||||
instance = createKryo();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.common.serialize.support.kryo;
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class ThreadLocalKryoFactory extends KryoFactory {
|
||||
|
||||
private final ThreadLocal<Kryo> holder = new ThreadLocal<Kryo>() {
|
||||
@Override
|
||||
protected Kryo initialValue() {
|
||||
return createKryo();
|
||||
}
|
||||
};
|
||||
|
||||
public Kryo getKryo() {
|
||||
return holder.get();
|
||||
}
|
||||
}
|
||||
|
|
@ -3,4 +3,6 @@ hessian2=com.alibaba.dubbo.common.serialize.support.hessian.Hessian2Serializatio
|
|||
java=com.alibaba.dubbo.common.serialize.support.java.JavaSerialization
|
||||
compactedjava=com.alibaba.dubbo.common.serialize.support.java.CompactedJavaSerialization
|
||||
fastjson=com.alibaba.dubbo.common.serialize.support.json.FastJsonSerialization
|
||||
nativejava=com.alibaba.dubbo.common.serialize.support.nativejava.NativeJavaSerialization
|
||||
nativejava=com.alibaba.dubbo.common.serialize.support.nativejava.NativeJavaSerialization
|
||||
kryo=com.alibaba.dubbo.common.serialize.support.kryo.KryoSerialization
|
||||
fst=com.alibaba.dubbo.common.serialize.support.fst.FstSerialization
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.alibaba.dubbo.common.serialize.serialization;
|
||||
|
||||
import com.alibaba.dubbo.common.serialize.support.kryo.KryoSerialization;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class FstSerializationTest extends AbstractSerializationTest {
|
||||
|
||||
{
|
||||
serialization = new KryoSerialization();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.alibaba.dubbo.common.serialize.serialization;
|
||||
|
||||
import com.alibaba.dubbo.common.serialize.support.kryo.KryoSerialization;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class KyroSerializationTest extends AbstractSerializationTest {
|
||||
|
||||
{
|
||||
serialization = new KryoSerialization();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.alibaba.dubbo.common.serialize.serialization;
|
||||
|
||||
import com.alibaba.dubbo.common.serialize.support.kryo.ReflectionUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class ReflectionUtilsTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
assertTrue(ReflectionUtils.checkZeroArgConstructor(String.class));
|
||||
assertTrue(ReflectionUtils.checkZeroArgConstructor(Bar.class));
|
||||
assertFalse(ReflectionUtils.checkZeroArgConstructor(Foo.class));
|
||||
}
|
||||
|
||||
static class Foo {
|
||||
public Foo(int i) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class Bar {
|
||||
private Bar() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -119,6 +119,16 @@ public class ProtocolConfig extends AbstractConfig {
|
|||
// whether to register
|
||||
private Boolean register;
|
||||
|
||||
// parameters
|
||||
// 是否长连接
|
||||
// TODO add this to provider config
|
||||
private Boolean keepAlive;
|
||||
|
||||
// TODO add this to provider config
|
||||
private String optimizer;
|
||||
|
||||
private String extension;
|
||||
|
||||
// parameters
|
||||
private Map<String, String> parameters;
|
||||
|
||||
|
|
@ -443,6 +453,30 @@ public class ProtocolConfig extends AbstractConfig {
|
|||
this.isDefault = isDefault;
|
||||
}
|
||||
|
||||
public Boolean getKeepAlive() {
|
||||
return keepAlive;
|
||||
}
|
||||
|
||||
public void setKeepAlive(Boolean keepAlive) {
|
||||
this.keepAlive = keepAlive;
|
||||
}
|
||||
|
||||
public String getOptimizer() {
|
||||
return optimizer;
|
||||
}
|
||||
|
||||
public void setOptimizer(String optimizer) {
|
||||
this.optimizer = optimizer;
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
return extension;
|
||||
}
|
||||
|
||||
public void setExtension(String extension) {
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
public void destory() {
|
||||
if (name != null) {
|
||||
ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).destroy();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import com.alibaba.dubbo.rpc.Exporter;
|
|||
import com.alibaba.dubbo.rpc.Invoker;
|
||||
import com.alibaba.dubbo.rpc.Protocol;
|
||||
import com.alibaba.dubbo.rpc.ProxyFactory;
|
||||
import com.alibaba.dubbo.rpc.ServiceClassHolder;
|
||||
import com.alibaba.dubbo.rpc.cluster.ConfiguratorFactory;
|
||||
import com.alibaba.dubbo.rpc.service.GenericService;
|
||||
import com.alibaba.dubbo.rpc.support.ProtocolUtils;
|
||||
|
|
@ -523,6 +524,7 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
|
|||
.setProtocol(Constants.LOCAL_PROTOCOL)
|
||||
.setHost(LOCALHOST)
|
||||
.setPort(0);
|
||||
ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref));
|
||||
Exporter<?> exporter = protocol.export(
|
||||
proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
|
||||
exporters.add(exporter);
|
||||
|
|
@ -530,6 +532,9 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
|
|||
}
|
||||
}
|
||||
|
||||
protected Class getServiceClass(T ref) {
|
||||
return ref.getClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register & bind IP address for service provider, can be configured separately.
|
||||
|
|
|
|||
|
|
@ -804,6 +804,21 @@
|
|||
<xsd:documentation><![CDATA[ The protocol serialization. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="keepalive" type="xsd:boolean" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[ The protocol keepAlive. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="optimizer" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[ The serialization optimizer. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="extension" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[ The extension for protocol. ]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="charset" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[ The protocol charset. ]]></xsd:documentation>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.alibaba.dubbo.common.io.Bytes;
|
|||
import com.alibaba.dubbo.common.io.StreamUtils;
|
||||
import com.alibaba.dubbo.common.logger.Logger;
|
||||
import com.alibaba.dubbo.common.logger.LoggerFactory;
|
||||
import com.alibaba.dubbo.common.serialize.Cleanable;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectInput;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectOutput;
|
||||
import com.alibaba.dubbo.common.serialize.Serialization;
|
||||
|
|
@ -230,6 +231,9 @@ public class ExchangeCodec extends TelnetCodec {
|
|||
encodeRequestData(channel, out, req.getData());
|
||||
}
|
||||
out.flushBuffer();
|
||||
if (out instanceof Cleanable) {
|
||||
((Cleanable) out).cleanup();
|
||||
}
|
||||
bos.flush();
|
||||
bos.close();
|
||||
int len = bos.writtenBytes();
|
||||
|
|
@ -271,6 +275,9 @@ public class ExchangeCodec extends TelnetCodec {
|
|||
}
|
||||
} else out.writeUTF(res.getErrorMessage());
|
||||
out.flushBuffer();
|
||||
if (out instanceof Cleanable) {
|
||||
((Cleanable) out).cleanup();
|
||||
}
|
||||
bos.flush();
|
||||
bos.close();
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package com.alibaba.dubbo.remoting.transport.codec;
|
||||
|
||||
import com.alibaba.dubbo.common.serialize.Cleanable;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectInput;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectOutput;
|
||||
import com.alibaba.dubbo.common.utils.StringUtils;
|
||||
|
|
@ -39,11 +40,19 @@ public class TransportCodec extends AbstractCodec {
|
|||
ObjectOutput objectOutput = getSerialization(channel).serialize(channel.getUrl(), output);
|
||||
encodeData(channel, objectOutput, message);
|
||||
objectOutput.flushBuffer();
|
||||
if (objectOutput instanceof Cleanable) {
|
||||
((Cleanable) objectOutput).cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {
|
||||
InputStream input = new ChannelBufferInputStream(buffer);
|
||||
return decodeData(channel, getSerialization(channel).deserialize(channel.getUrl(), input));
|
||||
ObjectInput objectInput = getSerialization(channel).deserialize(channel.getUrl(), input);
|
||||
Object object = decodeData(channel, objectInput);
|
||||
if (objectInput instanceof Cleanable) {
|
||||
((Cleanable) objectInput).cleanup();
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
protected void encodeData(Channel channel, ObjectOutput output, Object message) throws IOException {
|
||||
|
|
|
|||
|
|
@ -39,5 +39,13 @@
|
|||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-logging-juli</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -23,12 +23,15 @@ import com.alibaba.dubbo.common.logger.LoggerFactory;
|
|||
import com.alibaba.dubbo.common.utils.NetUtils;
|
||||
import com.alibaba.dubbo.remoting.http.HttpHandler;
|
||||
import com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet;
|
||||
import com.alibaba.dubbo.remoting.http.servlet.ServletManager;
|
||||
import com.alibaba.dubbo.remoting.http.support.AbstractHttpServer;
|
||||
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.nio.SelectChannelConnector;
|
||||
import org.mortbay.jetty.servlet.Context;
|
||||
import org.mortbay.jetty.servlet.ServletHandler;
|
||||
import org.mortbay.jetty.servlet.ServletHolder;
|
||||
import org.mortbay.log.Log;
|
||||
import org.mortbay.log.StdErrLog;
|
||||
import org.mortbay.thread.QueuedThreadPool;
|
||||
|
||||
public class JettyHttpServer extends AbstractHttpServer {
|
||||
|
|
@ -36,9 +39,16 @@ public class JettyHttpServer extends AbstractHttpServer {
|
|||
private static final Logger logger = LoggerFactory.getLogger(JettyHttpServer.class);
|
||||
|
||||
private Server server;
|
||||
|
||||
private URL url;
|
||||
|
||||
public JettyHttpServer(URL url, final HttpHandler handler) {
|
||||
super(url, handler);
|
||||
this.url = url;
|
||||
// TODO we should leave this setting to slf4j
|
||||
Log.setLog(new StdErrLog());
|
||||
Log.getLog().setDebugEnabled(false);
|
||||
|
||||
DispatcherServlet.addHttpHandler(url.getParameter(Constants.BIND_PORT_KEY, url.getPort()), handler);
|
||||
|
||||
int threads = url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS);
|
||||
|
|
@ -62,8 +72,13 @@ public class JettyHttpServer extends AbstractHttpServer {
|
|||
ServletHandler servletHandler = new ServletHandler();
|
||||
ServletHolder servletHolder = servletHandler.addServletWithMapping(DispatcherServlet.class, "/*");
|
||||
servletHolder.setInitOrder(2);
|
||||
|
||||
server.addHandler(servletHandler);
|
||||
|
||||
// dubbo's original impl can't support the use of ServletContext
|
||||
// server.addHandler(servletHandler);
|
||||
// TODO Context.SESSIONS is the best option here?
|
||||
Context context = new Context(server, "/", Context.SESSIONS);
|
||||
context.setServletHandler(servletHandler);
|
||||
ServletManager.getInstance().addServletContext(url.getPort(), context.getServletContext());
|
||||
|
||||
try {
|
||||
server.start();
|
||||
|
|
@ -75,6 +90,7 @@ public class JettyHttpServer extends AbstractHttpServer {
|
|||
|
||||
public void close() {
|
||||
super.close();
|
||||
ServletManager.getInstance().removeServletContext(url.getPort());
|
||||
if (server != null) {
|
||||
try {
|
||||
server.stop();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.remoting.http.servlet;
|
||||
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
/**
|
||||
* This class must be defined before something like spring's ContextLoaderListener in web.xml
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
public class BootstrapListener implements ServletContextListener {
|
||||
|
||||
public void contextInitialized(ServletContextEvent servletContextEvent) {
|
||||
ServletManager.getInstance().addServletContext(ServletManager.EXTERNAL_SERVER_PORT, servletContextEvent.getServletContext());
|
||||
}
|
||||
|
||||
public void contextDestroyed(ServletContextEvent servletContextEvent) {
|
||||
ServletManager.getInstance().removeServletContext(ServletManager.EXTERNAL_SERVER_PORT);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.remoting.http.servlet;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* TODO this may not be a pretty elegant solution,
|
||||
* and we may need to make change to the whole remoting-http architecture in the future
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
public class ServletManager {
|
||||
|
||||
public static final int EXTERNAL_SERVER_PORT = -1234;
|
||||
|
||||
private static final ServletManager instance = new ServletManager();
|
||||
|
||||
private final Map<Integer, ServletContext> contextMap = new ConcurrentHashMap<Integer, ServletContext>();
|
||||
|
||||
public static ServletManager getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void addServletContext(int port, ServletContext servletContext) {
|
||||
contextMap.put(port, servletContext);
|
||||
}
|
||||
|
||||
public void removeServletContext(int port) {
|
||||
contextMap.remove(port);
|
||||
}
|
||||
|
||||
public ServletContext getServletContext(int port) {
|
||||
return contextMap.get(port);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.remoting.http.tomcat;
|
||||
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import com.alibaba.dubbo.remoting.http.HttpBinder;
|
||||
import com.alibaba.dubbo.remoting.http.HttpHandler;
|
||||
import com.alibaba.dubbo.remoting.http.HttpServer;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class TomcatHttpBinder implements HttpBinder {
|
||||
|
||||
public HttpServer bind(URL url, HttpHandler handler) {
|
||||
return new TomcatHttpServer(url, handler);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.remoting.http.tomcat;
|
||||
|
||||
|
||||
import com.alibaba.dubbo.common.Constants;
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import com.alibaba.dubbo.common.logger.Logger;
|
||||
import com.alibaba.dubbo.common.logger.LoggerFactory;
|
||||
import com.alibaba.dubbo.remoting.http.HttpHandler;
|
||||
import com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet;
|
||||
import com.alibaba.dubbo.remoting.http.servlet.ServletManager;
|
||||
import com.alibaba.dubbo.remoting.http.support.AbstractHttpServer;
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class TomcatHttpServer extends AbstractHttpServer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TomcatHttpServer.class);
|
||||
|
||||
private final Tomcat tomcat;
|
||||
|
||||
private final URL url;
|
||||
|
||||
public TomcatHttpServer(URL url, final HttpHandler handler) {
|
||||
super(url, handler);
|
||||
|
||||
this.url = url;
|
||||
DispatcherServlet.addHttpHandler(url.getPort(), handler);
|
||||
String baseDir = new File(System.getProperty("java.io.tmpdir")).getAbsolutePath();
|
||||
tomcat = new Tomcat();
|
||||
tomcat.setBaseDir(baseDir);
|
||||
tomcat.setPort(url.getPort());
|
||||
tomcat.getConnector().setProperty(
|
||||
"maxThreads", String.valueOf(url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS)));
|
||||
// tomcat.getConnector().setProperty(
|
||||
// "minSpareThreads", String.valueOf(url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS)));
|
||||
|
||||
tomcat.getConnector().setProperty(
|
||||
"maxConnections", String.valueOf(url.getParameter(Constants.ACCEPTS_KEY, -1)));
|
||||
|
||||
tomcat.getConnector().setProperty("URIEncoding", "UTF-8");
|
||||
tomcat.getConnector().setProperty("connectionTimeout", "60000");
|
||||
|
||||
tomcat.getConnector().setProperty("maxKeepAliveRequests", "-1");
|
||||
tomcat.getConnector().setProtocol("org.apache.coyote.http11.Http11NioProtocol");
|
||||
|
||||
Context context = tomcat.addContext("/", baseDir);
|
||||
Tomcat.addServlet(context, "dispatcher", new DispatcherServlet());
|
||||
context.addServletMapping("/*", "dispatcher");
|
||||
ServletManager.getInstance().addServletContext(url.getPort(), context.getServletContext());
|
||||
|
||||
try {
|
||||
tomcat.start();
|
||||
} catch (LifecycleException e) {
|
||||
throw new IllegalStateException("Failed to start tomcat server at " + url.getAddress(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
super.close();
|
||||
|
||||
ServletManager.getInstance().removeServletContext(url.getPort());
|
||||
|
||||
try {
|
||||
tomcat.stop();
|
||||
} catch (Exception e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +1,3 @@
|
|||
servlet=com.alibaba.dubbo.remoting.http.servlet.ServletHttpBinder
|
||||
jetty=com.alibaba.dubbo.remoting.http.jetty.JettyHttpBinder
|
||||
jetty=com.alibaba.dubbo.remoting.http.jetty.JettyHttpBinder
|
||||
tomcat=com.alibaba.dubbo.remoting.http.tomcat.TomcatHttpBinder
|
||||
|
|
@ -68,6 +68,13 @@ public class RpcContext {
|
|||
private InetSocketAddress localAddress;
|
||||
|
||||
private InetSocketAddress remoteAddress;
|
||||
|
||||
// now we don't use the 'values' map to hold these objects
|
||||
// we want these objects to be as generic as possible
|
||||
private Object request;
|
||||
|
||||
private Object response;
|
||||
|
||||
@Deprecated
|
||||
private List<Invoker<?>> invokers;
|
||||
@Deprecated
|
||||
|
|
@ -78,6 +85,32 @@ public class RpcContext {
|
|||
protected RpcContext() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the request object of the underlying RPC protocol, e.g. HttServletRequest
|
||||
*
|
||||
* @return null if the underlying protocol doesn't provide support for getting request
|
||||
*/
|
||||
public Object getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public void setRequest(Object request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response object of the underlying RPC protocol, e.g. HttServletResponse
|
||||
*
|
||||
* @return null if the underlying protocol doesn't provide support for getting response
|
||||
*/
|
||||
public Object getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
public void setResponse(Object response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
/**
|
||||
* get context.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package com.alibaba.dubbo.rpc;
|
||||
|
||||
/**
|
||||
* TODO this is just a workround for rest protocol, and now we just ensure it works in the most common dubbo usages
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
public class ServiceClassHolder {
|
||||
|
||||
private static final ServiceClassHolder INSTANCE = new ServiceClassHolder();
|
||||
|
||||
private final ThreadLocal<Class> holder = new ThreadLocal<Class>();
|
||||
|
||||
public static ServiceClassHolder getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private ServiceClassHolder() {
|
||||
}
|
||||
|
||||
public Class popServiceClass() {
|
||||
Class clazz = holder.get();
|
||||
holder.remove();
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public void pushServiceClass(Class clazz) {
|
||||
holder.set(clazz);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ package com.alibaba.dubbo.rpc.protocol.dubbo;
|
|||
import com.alibaba.dubbo.common.Constants;
|
||||
import com.alibaba.dubbo.common.logger.Logger;
|
||||
import com.alibaba.dubbo.common.logger.LoggerFactory;
|
||||
import com.alibaba.dubbo.common.serialize.Cleanable;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectInput;
|
||||
import com.alibaba.dubbo.common.utils.Assert;
|
||||
import com.alibaba.dubbo.common.utils.ReflectUtils;
|
||||
|
|
@ -94,19 +95,40 @@ public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Dec
|
|||
try {
|
||||
Object[] args;
|
||||
Class<?>[] pts;
|
||||
String desc = in.readUTF();
|
||||
if (desc.length() == 0) {
|
||||
pts = DubboCodec.EMPTY_CLASS_ARRAY;
|
||||
args = DubboCodec.EMPTY_OBJECT_ARRAY;
|
||||
int argNum = in.readInt();
|
||||
if (argNum >= 0) {
|
||||
if (argNum == 0) {
|
||||
pts = DubboCodec.EMPTY_CLASS_ARRAY;
|
||||
args = DubboCodec.EMPTY_OBJECT_ARRAY;
|
||||
} else {
|
||||
args = new Object[argNum];
|
||||
pts = new Class[argNum];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
try {
|
||||
args[i] = in.readObject();
|
||||
pts[i] = args[i].getClass();
|
||||
} catch (Exception e) {
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn("Decode argument failed: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pts = ReflectUtils.desc2classArray(desc);
|
||||
args = new Object[pts.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
try {
|
||||
args[i] = in.readObject(pts[i]);
|
||||
} catch (Exception e) {
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn("Decode argument failed: " + e.getMessage(), e);
|
||||
String desc = in.readUTF();
|
||||
if (desc.length() == 0) {
|
||||
pts = DubboCodec.EMPTY_CLASS_ARRAY;
|
||||
args = DubboCodec.EMPTY_OBJECT_ARRAY;
|
||||
} else {
|
||||
pts = ReflectUtils.desc2classArray(desc);
|
||||
args = new Object[pts.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
try {
|
||||
args[i] = in.readObject(pts[i]);
|
||||
} catch (Exception e) {
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn("Decode argument failed: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -131,6 +153,10 @@ public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Dec
|
|||
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IOException(StringUtils.toString("Read invocation data failed.", e));
|
||||
} finally {
|
||||
if (in instanceof Cleanable) {
|
||||
((Cleanable) in).cleanup();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package com.alibaba.dubbo.rpc.protocol.dubbo;
|
|||
|
||||
import com.alibaba.dubbo.common.logger.Logger;
|
||||
import com.alibaba.dubbo.common.logger.LoggerFactory;
|
||||
import com.alibaba.dubbo.common.serialize.Cleanable;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectInput;
|
||||
import com.alibaba.dubbo.common.utils.Assert;
|
||||
import com.alibaba.dubbo.common.utils.StringUtils;
|
||||
|
|
@ -69,7 +70,7 @@ public class DecodeableRpcResult extends RpcResult implements Codec, Decodeable
|
|||
public Object decode(Channel channel, InputStream input) throws IOException {
|
||||
ObjectInput in = CodecSupport.getSerialization(channel.getUrl(), serializationType)
|
||||
.deserialize(channel.getUrl(), input);
|
||||
|
||||
|
||||
byte flag = in.readByte();
|
||||
switch (flag) {
|
||||
case DubboCodec.RESPONSE_NULL_VALUE:
|
||||
|
|
@ -97,6 +98,9 @@ public class DecodeableRpcResult extends RpcResult implements Codec, Decodeable
|
|||
default:
|
||||
throw new IOException("Unknown result flag, expect '0' '1' '2', get " + flag);
|
||||
}
|
||||
if (in instanceof Cleanable) {
|
||||
((Cleanable) in).cleanup();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import com.alibaba.dubbo.common.logger.Logger;
|
|||
import com.alibaba.dubbo.common.logger.LoggerFactory;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectInput;
|
||||
import com.alibaba.dubbo.common.serialize.ObjectOutput;
|
||||
import com.alibaba.dubbo.common.serialize.OptimizedSerialization;
|
||||
import com.alibaba.dubbo.common.serialize.Serialization;
|
||||
import com.alibaba.dubbo.common.utils.ReflectUtils;
|
||||
import com.alibaba.dubbo.common.utils.StringUtils;
|
||||
|
|
@ -168,7 +169,14 @@ public class DubboCodec extends ExchangeCodec implements Codec2 {
|
|||
out.writeUTF(inv.getAttachment(Constants.VERSION_KEY));
|
||||
|
||||
out.writeUTF(inv.getMethodName());
|
||||
out.writeUTF(ReflectUtils.getDesc(inv.getParameterTypes()));
|
||||
|
||||
if (getSerialization(channel) instanceof OptimizedSerialization && !containComplexArguments(inv)) {
|
||||
out.writeInt(inv.getParameterTypes().length);
|
||||
} else {
|
||||
out.writeInt(-1);
|
||||
out.writeUTF(ReflectUtils.getDesc(inv.getParameterTypes()));
|
||||
}
|
||||
|
||||
Object[] args = inv.getArguments();
|
||||
if (args != null)
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
|
|
@ -195,4 +203,14 @@ public class DubboCodec extends ExchangeCodec implements Codec2 {
|
|||
out.writeObject(th);
|
||||
}
|
||||
}
|
||||
|
||||
// workaround for the target method matching of kryo & fst
|
||||
private boolean containComplexArguments(RpcInvocation invocation) {
|
||||
for (int i = 0; i < invocation.getParameterTypes().length; i++) {
|
||||
if (invocation.getArguments()[i] == null || invocation.getParameterTypes()[i] != invocation.getArguments()[i].getClass()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,8 +18,10 @@ package com.alibaba.dubbo.rpc.protocol.dubbo;
|
|||
|
||||
import com.alibaba.dubbo.common.Constants;
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import com.alibaba.dubbo.common.Version;
|
||||
import com.alibaba.dubbo.common.extension.ExtensionLoader;
|
||||
import com.alibaba.dubbo.common.serialize.support.SerializableClassRegistry;
|
||||
import com.alibaba.dubbo.common.serialize.support.SerializationOptimizer;
|
||||
import com.alibaba.dubbo.common.utils.ConcurrentHashSet;
|
||||
import com.alibaba.dubbo.common.utils.NetUtils;
|
||||
import com.alibaba.dubbo.common.utils.StringUtils;
|
||||
import com.alibaba.dubbo.remoting.Channel;
|
||||
|
|
@ -62,6 +64,7 @@ public class DubboProtocol extends AbstractProtocol {
|
|||
private final Map<String, ExchangeServer> serverMap = new ConcurrentHashMap<String, ExchangeServer>(); // <host:port,Exchanger>
|
||||
private final Map<String, ReferenceCountExchangeClient> referenceClientMap = new ConcurrentHashMap<String, ReferenceCountExchangeClient>(); // <host:port,Exchanger>
|
||||
private final ConcurrentMap<String, LazyConnectExchangeClient> ghostClientMap = new ConcurrentHashMap<String, LazyConnectExchangeClient>();
|
||||
private final Set<String> optimizers = new ConcurrentHashSet<String>();
|
||||
//consumer side export a stub service for dispatching event
|
||||
//servicekey-stubmethods
|
||||
private final ConcurrentMap<String, String> stubServiceMethodsMap = new ConcurrentHashMap<String, String>();
|
||||
|
|
@ -236,7 +239,7 @@ public class DubboProtocol extends AbstractProtocol {
|
|||
}
|
||||
|
||||
openServer(url);
|
||||
|
||||
optimizeSerialization(url);
|
||||
return exporter;
|
||||
}
|
||||
|
||||
|
|
@ -283,7 +286,42 @@ public class DubboProtocol extends AbstractProtocol {
|
|||
return server;
|
||||
}
|
||||
|
||||
private void optimizeSerialization(URL url) throws RpcException {
|
||||
String className = url.getParameter(Constants.OPTIMIZER_KEY, "");
|
||||
if (StringUtils.isEmpty(className) || optimizers.contains(className)) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("Optimizing the serialization process for Kryo, FST, etc...");
|
||||
|
||||
try {
|
||||
Class clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
|
||||
if (!SerializationOptimizer.class.isAssignableFrom(clazz)) {
|
||||
throw new RpcException("The serialization optimizer " + className + " isn't an instance of " + SerializationOptimizer.class.getName());
|
||||
}
|
||||
|
||||
SerializationOptimizer optimizer = (SerializationOptimizer) clazz.newInstance();
|
||||
|
||||
if (optimizer.getSerializableClasses() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Class c : optimizer.getSerializableClasses()) {
|
||||
SerializableClassRegistry.registerClass(c);
|
||||
}
|
||||
|
||||
optimizers.add(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RpcException("Cannot find the serialization optimizer class: " + className, e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RpcException("Cannot instantiate the serialization optimizer class: " + className, e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RpcException("Cannot instantiate the serialization optimizer class: " + className, e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
|
||||
optimizeSerialization(url);
|
||||
// create rpc invoker.
|
||||
DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
|
||||
invokers.add(invoker);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
<!--
|
||||
- Copyright 1999-2011 Alibaba Group.
|
||||
-
|
||||
- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
- you may not use this file except in compliance with the License.
|
||||
- You may obtain a copy of the License at
|
||||
-
|
||||
- http://www.apache.org/licenses/LICENSE-2.0
|
||||
-
|
||||
- Unless required by applicable law or agreed to in writing, software
|
||||
- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
- See the License for the specific language governing permissions and
|
||||
- limitations under the License.
|
||||
-->
|
||||
<project xmlns="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/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo-rpc</artifactId>
|
||||
<version>2.5.8</version>
|
||||
</parent>
|
||||
<artifactId>dubbo-rpc-rest</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>The JAX-RS rpc module of dubbo project</description>
|
||||
<properties>
|
||||
<skip_maven_deploy>true</skip_maven_deploy>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo-rpc-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo-remoting-http</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxrs</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- optional dependencies ==================== -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-netty</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jdk-http</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>org.jboss.resteasy</groupId>-->
|
||||
<!--<artifactId>tjws</artifactId>-->
|
||||
<!--<version>3.0.7.Final</version>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>org.jboss.resteasy</groupId>-->
|
||||
<!--<artifactId>resteasy-undertow</artifactId>-->
|
||||
<!--<version>3.0.7.Final</version>-->
|
||||
<!--</dependency>-->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>io.undertow</groupId>-->
|
||||
<!--<artifactId>undertow-servlet</artifactId>-->
|
||||
<!--<version>1.0.1.Final</version>-->
|
||||
<!--</dependency>-->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>io.undertow</groupId>-->
|
||||
<!--<artifactId>undertow-core</artifactId>-->
|
||||
<!--<version>1.0.1.Final</version>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jackson-provider</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxb-provider</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import com.alibaba.dubbo.common.Constants;
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import com.alibaba.dubbo.common.utils.StringUtils;
|
||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public abstract class BaseRestServer implements RestServer {
|
||||
|
||||
public void start(URL url) {
|
||||
getDeployment().getMediaTypeMappings().put("json", "application/json");
|
||||
getDeployment().getMediaTypeMappings().put("xml", "text/xml");
|
||||
// server.getDeployment().getMediaTypeMappings().put("xml", "application/xml");
|
||||
getDeployment().getProviderClasses().add(RpcContextFilter.class.getName());
|
||||
// TODO users can override this mapper, but we just rely on the current priority strategy of resteasy
|
||||
getDeployment().getProviderClasses().add(RpcExceptionMapper.class.getName());
|
||||
|
||||
loadProviders(url.getParameter(Constants.EXTENSION_KEY, ""));
|
||||
|
||||
doStart(url);
|
||||
}
|
||||
|
||||
public void deploy(Class resourceDef, Object resourceInstance, String contextPath) {
|
||||
if (StringUtils.isEmpty(contextPath)) {
|
||||
getDeployment().getRegistry().addResourceFactory(new DubboResourceFactory(resourceInstance, resourceDef));
|
||||
} else {
|
||||
getDeployment().getRegistry().addResourceFactory(new DubboResourceFactory(resourceInstance, resourceDef), contextPath);
|
||||
}
|
||||
}
|
||||
|
||||
public void undeploy(Class resourceDef) {
|
||||
getDeployment().getRegistry().removeRegistrations(resourceDef);
|
||||
}
|
||||
|
||||
protected void loadProviders(String value) {
|
||||
for (String clazz : Constants.COMMA_SPLIT_PATTERN.split(value)) {
|
||||
if (!StringUtils.isEmpty(clazz)) {
|
||||
getDeployment().getProviderClasses().add(clazz.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract ResteasyDeployment getDeployment();
|
||||
|
||||
protected abstract void doStart(URL url);
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import com.alibaba.dubbo.remoting.http.HttpBinder;
|
||||
import com.alibaba.dubbo.remoting.http.HttpHandler;
|
||||
import com.alibaba.dubbo.remoting.http.HttpServer;
|
||||
import com.alibaba.dubbo.remoting.http.servlet.BootstrapListener;
|
||||
import com.alibaba.dubbo.remoting.http.servlet.ServletManager;
|
||||
import com.alibaba.dubbo.rpc.RpcContext;
|
||||
import com.alibaba.dubbo.rpc.RpcException;
|
||||
import org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher;
|
||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class DubboHttpServer extends BaseRestServer {
|
||||
|
||||
private final HttpServletDispatcher dispatcher = new HttpServletDispatcher();
|
||||
private final ResteasyDeployment deployment = new ResteasyDeployment();
|
||||
private HttpBinder httpBinder;
|
||||
private HttpServer httpServer;
|
||||
// private boolean isExternalServer;
|
||||
|
||||
public DubboHttpServer(HttpBinder httpBinder) {
|
||||
this.httpBinder = httpBinder;
|
||||
}
|
||||
|
||||
protected void doStart(URL url) {
|
||||
// TODO jetty will by default enable keepAlive so the xml config has no effect now
|
||||
httpServer = httpBinder.bind(url, new RestHandler());
|
||||
|
||||
ServletContext servletContext = ServletManager.getInstance().getServletContext(url.getPort());
|
||||
if (servletContext == null) {
|
||||
servletContext = ServletManager.getInstance().getServletContext(ServletManager.EXTERNAL_SERVER_PORT);
|
||||
}
|
||||
if (servletContext == null) {
|
||||
throw new RpcException("No servlet context found. If you are using server='servlet', " +
|
||||
"make sure that you've configured " + BootstrapListener.class.getName() + " in web.xml");
|
||||
}
|
||||
|
||||
servletContext.setAttribute(ResteasyDeployment.class.getName(), deployment);
|
||||
|
||||
try {
|
||||
dispatcher.init(new SimpleServletConfig(servletContext));
|
||||
} catch (ServletException e) {
|
||||
throw new RpcException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
httpServer.close();
|
||||
}
|
||||
|
||||
protected ResteasyDeployment getDeployment() {
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private class RestHandler implements HttpHandler {
|
||||
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort());
|
||||
dispatcher.service(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SimpleServletConfig implements ServletConfig {
|
||||
|
||||
private final ServletContext servletContext;
|
||||
|
||||
public SimpleServletConfig(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
public String getServletName() {
|
||||
return "DispatcherServlet";
|
||||
}
|
||||
|
||||
public ServletContext getServletContext() {
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
public String getInitParameter(String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Enumeration getInitParameterNames() {
|
||||
return new Enumeration() {
|
||||
public boolean hasMoreElements() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object nextElement() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.jboss.resteasy.spi.HttpResponse;
|
||||
import org.jboss.resteasy.spi.ResourceFactory;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
|
||||
/**
|
||||
* We don't support propertyInjector here since the resource impl should be singleton in dubbo
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
public class DubboResourceFactory implements ResourceFactory {
|
||||
|
||||
private Object resourceInstance;
|
||||
private Class scannableClass;
|
||||
// private PropertyInjector propertyInjector;
|
||||
// private String context = null;
|
||||
|
||||
public DubboResourceFactory(Object resourceInstance, Class scannableClass) {
|
||||
this.resourceInstance = resourceInstance;
|
||||
this.scannableClass = scannableClass;
|
||||
}
|
||||
|
||||
// public PropertyInjector getPropertyInjector() {
|
||||
// return propertyInjector;
|
||||
// }
|
||||
|
||||
public Object createResource(HttpRequest request, HttpResponse response,
|
||||
ResteasyProviderFactory factory) {
|
||||
return resourceInstance;
|
||||
}
|
||||
|
||||
public Class<?> getScannableClass() {
|
||||
return scannableClass;
|
||||
}
|
||||
|
||||
public void registered(ResteasyProviderFactory factory) {
|
||||
// this.propertyInjector = factory.getInjectorFactory().createPropertyInjector(getScannableClass(), factory);
|
||||
}
|
||||
|
||||
public void requestFinished(HttpRequest request, HttpResponse response,
|
||||
Object resource) {
|
||||
}
|
||||
|
||||
public void unregistered() {
|
||||
}
|
||||
|
||||
// public void setContext(String context) {
|
||||
// this.context = context;
|
||||
// }
|
||||
//
|
||||
// public String getContext() {
|
||||
// return context;
|
||||
// }
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import com.alibaba.dubbo.common.Constants;
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import org.jboss.resteasy.plugins.server.netty.NettyJaxrsServer;
|
||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||
|
||||
/**
|
||||
* Netty server can't support @Context injection of servlet objects since it's not a servlet container
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
public class NettyServer extends BaseRestServer {
|
||||
|
||||
private final NettyJaxrsServer server = new NettyJaxrsServer();
|
||||
|
||||
protected void doStart(URL url) {
|
||||
server.setPort(url.getPort());
|
||||
server.setKeepAlive(url.getParameter(Constants.KEEP_ALIVE_KEY, true));
|
||||
server.setExecutorThreadCount(url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS));
|
||||
server.setIoWorkerCount(url.getParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
|
||||
server.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
protected ResteasyDeployment getDeployment() {
|
||||
return server.getDeployment();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
@XmlRootElement(name = "constraintViolation")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class RestConstraintViolation implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -23497234978L;
|
||||
|
||||
private String path;
|
||||
private String message;
|
||||
private String value;
|
||||
|
||||
public RestConstraintViolation(String path, String message, String value) {
|
||||
this.path = path;
|
||||
this.message = message;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public RestConstraintViolation() {
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import com.alibaba.dubbo.common.Constants;
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import com.alibaba.dubbo.common.utils.StringUtils;
|
||||
import com.alibaba.dubbo.remoting.http.HttpBinder;
|
||||
import com.alibaba.dubbo.remoting.http.servlet.BootstrapListener;
|
||||
import com.alibaba.dubbo.remoting.http.servlet.ServletManager;
|
||||
import com.alibaba.dubbo.rpc.RpcException;
|
||||
import com.alibaba.dubbo.rpc.protocol.AbstractProxyProtocol;
|
||||
import com.alibaba.dubbo.rpc.ServiceClassHolder;
|
||||
import org.apache.http.HeaderElement;
|
||||
import org.apache.http.HeaderElementIterator;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.conn.ClientConnectionManager;
|
||||
import org.apache.http.conn.ConnectionKeepAliveStrategy;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.impl.conn.PoolingClientConnectionManager;
|
||||
import org.apache.http.message.BasicHeaderElementIterator;
|
||||
import org.apache.http.params.HttpConnectionParams;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
|
||||
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
|
||||
import org.jboss.resteasy.util.GetRestful;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.ws.rs.ProcessingException;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class RestProtocol extends AbstractProxyProtocol {
|
||||
|
||||
private static final int DEFAULT_PORT = 80;
|
||||
|
||||
private final Map<String, RestServer> servers = new ConcurrentHashMap<String, RestServer>();
|
||||
|
||||
private final RestServerFactory serverFactory = new RestServerFactory();
|
||||
|
||||
// TODO in the future maybe we can just use a single rest client and connection manager
|
||||
private final List<ResteasyClient> clients = Collections.synchronizedList(new LinkedList<ResteasyClient>());
|
||||
|
||||
private volatile ConnectionMonitor connectionMonitor;
|
||||
|
||||
public RestProtocol() {
|
||||
super(WebApplicationException.class, ProcessingException.class);
|
||||
}
|
||||
|
||||
public void setHttpBinder(HttpBinder httpBinder) {
|
||||
serverFactory.setHttpBinder(httpBinder);
|
||||
}
|
||||
|
||||
public int getDefaultPort() {
|
||||
return DEFAULT_PORT;
|
||||
}
|
||||
|
||||
protected <T> Runnable doExport(T impl, Class<T> type, URL url) throws RpcException {
|
||||
String addr = url.getIp() + ":" + url.getPort();
|
||||
Class implClass = ServiceClassHolder.getInstance().popServiceClass();
|
||||
RestServer server = servers.get(addr);
|
||||
if (server == null) {
|
||||
server = serverFactory.createServer(url.getParameter(Constants.SERVER_KEY, "jetty"));
|
||||
server.start(url);
|
||||
servers.put(addr, server);
|
||||
}
|
||||
|
||||
String contextPath = getContextPath(url);
|
||||
if ("servlet".equalsIgnoreCase(url.getParameter(Constants.SERVER_KEY, "jetty"))) {
|
||||
ServletContext servletContext = ServletManager.getInstance().getServletContext(ServletManager.EXTERNAL_SERVER_PORT);
|
||||
if (servletContext == null) {
|
||||
throw new RpcException("No servlet context found. Since you are using server='servlet', " +
|
||||
"make sure that you've configured " + BootstrapListener.class.getName() + " in web.xml");
|
||||
}
|
||||
String webappPath = servletContext.getContextPath();
|
||||
if (StringUtils.isNotEmpty(webappPath)) {
|
||||
webappPath = webappPath.substring(1);
|
||||
if (!contextPath.startsWith(webappPath)) {
|
||||
throw new RpcException("Since you are using server='servlet', " +
|
||||
"make sure that the 'contextpath' property starts with the path of external webapp");
|
||||
}
|
||||
contextPath = contextPath.substring(webappPath.length());
|
||||
if (contextPath.startsWith("/")) {
|
||||
contextPath = contextPath.substring(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Class resourceDef = GetRestful.getRootResourceClass(implClass) != null ? implClass : type;
|
||||
|
||||
server.deploy(resourceDef, impl, contextPath);
|
||||
|
||||
final RestServer s = server;
|
||||
return new Runnable() {
|
||||
public void run() {
|
||||
// TODO due to dubbo's current architecture,
|
||||
// it will be called from registry protocol in the shutdown process and won't appear in logs
|
||||
s.undeploy(resourceDef);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected <T> T doRefer(Class<T> serviceType, URL url) throws RpcException {
|
||||
if (connectionMonitor == null) {
|
||||
connectionMonitor = new ConnectionMonitor();
|
||||
}
|
||||
|
||||
// TODO more configs to add
|
||||
|
||||
PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
|
||||
// 20 is the default maxTotal of current PoolingClientConnectionManager
|
||||
connectionManager.setMaxTotal(url.getParameter(Constants.CONNECTIONS_KEY, 20));
|
||||
connectionManager.setDefaultMaxPerRoute(url.getParameter(Constants.CONNECTIONS_KEY, 20));
|
||||
|
||||
connectionMonitor.addConnectionManager(connectionManager);
|
||||
|
||||
// BasicHttpContext localContext = new BasicHttpContext();
|
||||
|
||||
DefaultHttpClient httpClient = new DefaultHttpClient(connectionManager);
|
||||
|
||||
httpClient.setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {
|
||||
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
|
||||
HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
|
||||
while (it.hasNext()) {
|
||||
HeaderElement he = it.nextElement();
|
||||
String param = he.getName();
|
||||
String value = he.getValue();
|
||||
if (value != null && param.equalsIgnoreCase("timeout")) {
|
||||
return Long.parseLong(value) * 1000;
|
||||
}
|
||||
}
|
||||
// TODO constant
|
||||
return 30 * 1000;
|
||||
}
|
||||
});
|
||||
|
||||
HttpParams params = httpClient.getParams();
|
||||
// TODO currently no xml config for Constants.CONNECT_TIMEOUT_KEY so we directly reuse Constants.TIMEOUT_KEY for now
|
||||
HttpConnectionParams.setConnectionTimeout(params, url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT));
|
||||
HttpConnectionParams.setSoTimeout(params, url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT));
|
||||
HttpConnectionParams.setTcpNoDelay(params, true);
|
||||
HttpConnectionParams.setSoKeepalive(params, true);
|
||||
|
||||
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient/*, localContext*/);
|
||||
|
||||
ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();
|
||||
clients.add(client);
|
||||
|
||||
client.register(RpcContextFilter.class);
|
||||
for (String clazz : Constants.COMMA_SPLIT_PATTERN.split(url.getParameter(Constants.EXTENSION_KEY, ""))) {
|
||||
if (!StringUtils.isEmpty(clazz)) {
|
||||
try {
|
||||
client.register(Thread.currentThread().getContextClassLoader().loadClass(clazz.trim()));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RpcException("Error loading JAX-RS extension class: " + clazz.trim(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO protocol
|
||||
ResteasyWebTarget target = client.target("http://" + url.getHost() + ":" + url.getPort() + "/" + getContextPath(url));
|
||||
return target.proxy(serviceType);
|
||||
}
|
||||
|
||||
protected int getErrorCode(Throwable e) {
|
||||
// TODO
|
||||
return super.getErrorCode(e);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
|
||||
if (connectionMonitor != null) {
|
||||
connectionMonitor.shutdown();
|
||||
}
|
||||
|
||||
for (Map.Entry<String, RestServer> entry : servers.entrySet()) {
|
||||
try {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Closing the rest server at " + entry.getKey());
|
||||
}
|
||||
entry.getValue().stop();
|
||||
} catch (Throwable t) {
|
||||
logger.warn("Error closing rest server", t);
|
||||
}
|
||||
}
|
||||
servers.clear();
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Closing rest clients");
|
||||
}
|
||||
for (ResteasyClient client : clients) {
|
||||
try {
|
||||
client.close();
|
||||
} catch (Throwable t) {
|
||||
logger.warn("Error closing rest client", t);
|
||||
}
|
||||
}
|
||||
clients.clear();
|
||||
}
|
||||
|
||||
protected String getContextPath(URL url) {
|
||||
int pos = url.getPath().lastIndexOf("/");
|
||||
return pos > 0 ? url.getPath().substring(0, pos) : "";
|
||||
}
|
||||
|
||||
protected class ConnectionMonitor extends Thread {
|
||||
private volatile boolean shutdown;
|
||||
private final List<ClientConnectionManager> connectionManagers = Collections.synchronizedList(new LinkedList<ClientConnectionManager>());
|
||||
|
||||
public void addConnectionManager(ClientConnectionManager connectionManager) {
|
||||
connectionManagers.add(connectionManager);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
while (!shutdown) {
|
||||
synchronized (this) {
|
||||
wait(1000);
|
||||
for (ClientConnectionManager connectionManager : connectionManagers) {
|
||||
connectionManager.closeExpiredConnections();
|
||||
// TODO constant
|
||||
connectionManager.closeIdleConnections(30, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
shutdown = true;
|
||||
connectionManagers.clear();
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public interface RestServer {
|
||||
|
||||
void start(URL url);
|
||||
|
||||
/**
|
||||
* @param resourceDef it could be either resource interface or resource impl
|
||||
*/
|
||||
void deploy(Class resourceDef, Object resourceInstance, String contextPath);
|
||||
|
||||
void undeploy(Class resourceDef);
|
||||
|
||||
void stop();
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import com.alibaba.dubbo.remoting.http.HttpBinder;
|
||||
|
||||
/**
|
||||
* Only the server that implements servlet container
|
||||
* could support something like @Context injection of servlet objects.
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
public class RestServerFactory {
|
||||
|
||||
private HttpBinder httpBinder;
|
||||
|
||||
public void setHttpBinder(HttpBinder httpBinder) {
|
||||
this.httpBinder = httpBinder;
|
||||
}
|
||||
|
||||
public RestServer createServer(String name) {
|
||||
// TODO move names to Constants
|
||||
if ("servlet".equalsIgnoreCase(name) || "jetty".equalsIgnoreCase(name) || "tomcat".equalsIgnoreCase(name)) {
|
||||
return new DubboHttpServer(httpBinder);
|
||||
// } else if ("tjws".equalsIgnoreCase(name)) {
|
||||
// return new TjwsServer();
|
||||
} else if ("netty".equalsIgnoreCase(name)) {
|
||||
return new NettyServer();
|
||||
} else if ("sunhttp".equalsIgnoreCase(name)) {
|
||||
return new SunHttpServer();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unrecognized server name: " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import com.alibaba.dubbo.common.utils.StringUtils;
|
||||
import com.alibaba.dubbo.rpc.RpcContext;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
|
||||
import javax.annotation.Priority;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.client.ClientRequestContext;
|
||||
import javax.ws.rs.client.ClientRequestFilter;
|
||||
import javax.ws.rs.container.ContainerRequestContext;
|
||||
import javax.ws.rs.container.ContainerRequestFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
@Priority(Integer.MIN_VALUE + 1)
|
||||
public class RpcContextFilter implements ContainerRequestFilter, ClientRequestFilter {
|
||||
|
||||
private static final String DUBBO_ATTACHMENT_HEADER = "Dubbo-Attachments";
|
||||
|
||||
// currently we use a single header to hold the attachments so that the total attachment size limit is about 8k
|
||||
private static final int MAX_HEADER_SIZE = 8 * 1024;
|
||||
|
||||
public void filter(ContainerRequestContext requestContext) throws IOException {
|
||||
HttpServletRequest request = ResteasyProviderFactory.getContextData(HttpServletRequest.class);
|
||||
RpcContext.getContext().setRequest(request);
|
||||
|
||||
// this only works for servlet containers
|
||||
if (request != null && RpcContext.getContext().getRemoteAddress() == null) {
|
||||
RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort());
|
||||
}
|
||||
|
||||
RpcContext.getContext().setResponse(ResteasyProviderFactory.getContextData(HttpServletResponse.class));
|
||||
|
||||
String headers = requestContext.getHeaderString(DUBBO_ATTACHMENT_HEADER);
|
||||
if (headers != null) {
|
||||
for (String header : headers.split(",")) {
|
||||
int index = header.indexOf("=");
|
||||
if (index > 0) {
|
||||
String key = header.substring(0, index);
|
||||
String value = header.substring(index + 1);
|
||||
if (!StringUtils.isEmpty(key)) {
|
||||
RpcContext.getContext().setAttachment(key.trim(), value.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void filter(ClientRequestContext requestContext) throws IOException {
|
||||
int size = 0;
|
||||
for (Map.Entry<String, String> entry : RpcContext.getContext().getAttachments().entrySet()) {
|
||||
if (entry.getValue().contains(",") || entry.getValue().contains("=")
|
||||
|| entry.getKey().contains(",") || entry.getKey().contains("=")) {
|
||||
throw new IllegalArgumentException("The attachments of " + RpcContext.class.getSimpleName() + " must not contain ',' or '=' when using rest protocol");
|
||||
}
|
||||
|
||||
// TODO for now we don't consider the differences of encoding and server limit
|
||||
size += entry.getValue().getBytes("UTF-8").length;
|
||||
if (size > MAX_HEADER_SIZE) {
|
||||
throw new IllegalArgumentException("The attachments of " + RpcContext.class.getSimpleName() + " is too big");
|
||||
}
|
||||
|
||||
StringBuilder attachments = new StringBuilder();
|
||||
attachments.append(entry.getKey());
|
||||
attachments.append("=");
|
||||
attachments.append(entry.getValue());
|
||||
requestContext.getHeaders().add(DUBBO_ATTACHMENT_HEADER, attachments.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import com.alibaba.dubbo.rpc.RpcException;
|
||||
import com.alibaba.dubbo.rpc.protocol.rest.support.ContentType;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class RpcExceptionMapper implements ExceptionMapper<RpcException> {
|
||||
|
||||
public Response toResponse(RpcException e) {
|
||||
// TODO do more sophisticated exception handling and output
|
||||
if (e.getCause() instanceof ConstraintViolationException) {
|
||||
return handleConstraintViolationException((ConstraintViolationException) e.getCause());
|
||||
}
|
||||
// we may want to avoid exposing the dubbo exception details to certain clients
|
||||
// TODO for now just do plain text output
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Internal server error: " + e.getMessage()).type(ContentType.TEXT_PLAIN_UTF_8).build();
|
||||
}
|
||||
|
||||
protected Response handleConstraintViolationException(ConstraintViolationException cve) {
|
||||
ViolationReport report = new ViolationReport();
|
||||
for (ConstraintViolation cv : cve.getConstraintViolations()) {
|
||||
report.addConstraintViolation(new RestConstraintViolation(
|
||||
cv.getPropertyPath().toString(),
|
||||
cv.getMessage(),
|
||||
cv.getInvalidValue() == null ? "null" : cv.getInvalidValue().toString()));
|
||||
}
|
||||
// TODO for now just do xml output
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(report).type(ContentType.TEXT_XML_UTF_8).build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import org.jboss.resteasy.plugins.server.sun.http.SunHttpJaxrsServer;
|
||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class SunHttpServer extends BaseRestServer {
|
||||
|
||||
private final SunHttpJaxrsServer server = new SunHttpJaxrsServer();
|
||||
|
||||
protected void doStart(URL url) {
|
||||
server.setPort(url.getPort());
|
||||
server.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
protected ResteasyDeployment getDeployment() {
|
||||
return server.getDeployment();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import com.alibaba.dubbo.common.URL;
|
||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class TjwsServer extends BaseRestServer {
|
||||
|
||||
// private final TJWSEmbeddedJaxrsServer server = new TJWSEmbeddedJaxrsServer();
|
||||
|
||||
protected void doStart(URL url) {
|
||||
throw new UnsupportedOperationException("TJWS server is now unsupported");
|
||||
// server.setPort(url.getPort());
|
||||
// // below config is useless due to a resteasy bug
|
||||
//// server.setKeepAlive(false);
|
||||
// server.start();
|
||||
}
|
||||
|
||||
protected ResteasyDeployment getDeployment() {
|
||||
throw new UnsupportedOperationException("TJWS server is now unsupported");
|
||||
// return server.getDeployment();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
throw new UnsupportedOperationException("TJWS server is now unsupported");
|
||||
// server.stop();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
//import com.alibaba.dubbo.common.URL;
|
||||
//import com.alibaba.dubbo.common.utils.StringUtils;
|
||||
//import io.undertow.Undertow;
|
||||
//import io.undertow.servlet.api.DeploymentInfo;
|
||||
//import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
|
||||
//import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||
|
||||
/**
|
||||
* TODO this impl hasn't been well tested, and we can consider move undertow to a general remoting-http impl in the future
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
public class UndertowServer /*implements RestServer*/ {
|
||||
|
||||
// // Note that UndertowJaxrsServer doesn't implement EmbeddedJaxrsServer
|
||||
//
|
||||
// private final ResteasyDeployment deployment = new ResteasyDeployment();
|
||||
//
|
||||
// private final UndertowJaxrsServer server = new UndertowJaxrsServer();
|
||||
//
|
||||
// public void start(URL url) {
|
||||
// deployment.start();
|
||||
// DeploymentInfo deploymentInfo = server.undertowDeployment(deployment);
|
||||
// deploymentInfo.setContextPath("/");
|
||||
// deploymentInfo.setDeploymentName("dubbo-rest");
|
||||
// deploymentInfo.setClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
// server.deploy(deploymentInfo);
|
||||
// server.start(Undertow.builder().addHttpListener(url.getPort(), url.getHost()));
|
||||
// }
|
||||
//
|
||||
// public void deploy(Class resourceDef, Object resourceInstance, String contextPath) {
|
||||
// if (StringUtils.isEmpty(contextPath)) {
|
||||
// deployment.getRegistry().addResourceFactory(new DubboResourceFactory(resourceInstance, resourceDef));
|
||||
// } else {
|
||||
// deployment.getRegistry().addResourceFactory(new DubboResourceFactory(resourceInstance, resourceDef), contextPath);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public void undeploy(Class resourceDef) {
|
||||
// deployment.getRegistry().removeRegistrations(resourceDef);
|
||||
// }
|
||||
//
|
||||
// public void deploy(Class resourceDef, Object resourceInstance) {
|
||||
// deploy(resourceDef, resourceInstance, "/");
|
||||
// }
|
||||
//
|
||||
// public void stop() {
|
||||
// deployment.stop();
|
||||
// server.stop();
|
||||
// }
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
@XmlRootElement(name="violationReport")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class ViolationReport implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -130498234L;
|
||||
|
||||
private List<RestConstraintViolation> constraintViolations;
|
||||
|
||||
public List<RestConstraintViolation> getConstraintViolations() {
|
||||
return constraintViolations;
|
||||
}
|
||||
|
||||
public void setConstraintViolations(List<RestConstraintViolation> constraintViolations) {
|
||||
this.constraintViolations = constraintViolations;
|
||||
}
|
||||
|
||||
public void addConstraintViolation(RestConstraintViolation constraintViolation) {
|
||||
if (constraintViolations == null) {
|
||||
constraintViolations = new LinkedList<RestConstraintViolation>();
|
||||
}
|
||||
constraintViolations.add(constraintViolation);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest.support;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
/**
|
||||
* @author lishen
|
||||
*/
|
||||
public class ContentType {
|
||||
|
||||
public static final String APPLICATION_JSON_UTF_8 = MediaType.APPLICATION_JSON + "; " + MediaType.CHARSET_PARAMETER + "=UTF-8";
|
||||
public static final String TEXT_XML_UTF_8 = MediaType.TEXT_XML + "; " + MediaType.CHARSET_PARAMETER + "=UTF-8";
|
||||
public static final String TEXT_PLAIN_UTF_8 = MediaType.TEXT_PLAIN + "; " + MediaType.CHARSET_PARAMETER + "=UTF-8";
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/**
|
||||
* Copyright 1999-2014 dangdang.com.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.dubbo.rpc.protocol.rest.support;
|
||||
|
||||
import com.alibaba.dubbo.common.logger.Logger;
|
||||
import com.alibaba.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import javax.annotation.Priority;
|
||||
import javax.ws.rs.Priorities;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.client.ClientRequestContext;
|
||||
import javax.ws.rs.client.ClientRequestFilter;
|
||||
import javax.ws.rs.client.ClientResponseContext;
|
||||
import javax.ws.rs.client.ClientResponseFilter;
|
||||
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 javax.ws.rs.core.MultivaluedMap;
|
||||
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.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This logging filter is not highly optimized for now
|
||||
*
|
||||
* @author lishen
|
||||
*/
|
||||
@Priority(Integer.MIN_VALUE)
|
||||
public class LoggingFilter implements ContainerRequestFilter, ClientRequestFilter, ContainerResponseFilter, ClientResponseFilter, WriterInterceptor, ReaderInterceptor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
|
||||
|
||||
public void filter(ClientRequestContext context) throws IOException {
|
||||
logHttpHeaders(context.getStringHeaders());
|
||||
}
|
||||
|
||||
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
|
||||
logHttpHeaders(responseContext.getHeaders());
|
||||
}
|
||||
|
||||
public void filter(ContainerRequestContext context) throws IOException {
|
||||
logHttpHeaders(context.getHeaders());
|
||||
}
|
||||
|
||||
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
|
||||
logHttpHeaders(responseContext.getStringHeaders());
|
||||
}
|
||||
|
||||
public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
|
||||
byte[] buffer = IOUtils.toByteArray(context.getInputStream());
|
||||
logger.info("The contents of request body is: \n" + new String(buffer, "UTF-8") + "\n");
|
||||
context.setInputStream(new ByteArrayInputStream(buffer));
|
||||
return context.proceed();
|
||||
}
|
||||
|
||||
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
|
||||
OutputStreamWrapper wrapper = new OutputStreamWrapper(context.getOutputStream());
|
||||
context.setOutputStream(wrapper);
|
||||
context.proceed();
|
||||
logger.info("The contents of response body is: \n" + new String(wrapper.getBytes(), "UTF-8") + "\n");
|
||||
}
|
||||
|
||||
protected void logHttpHeaders(MultivaluedMap<String, String> headers) {
|
||||
StringBuilder msg = new StringBuilder("The HTTP headers are: \n");
|
||||
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
|
||||
msg.append(entry.getKey()).append(": ");
|
||||
for (int i = 0; i < entry.getValue().size(); i++) {
|
||||
msg.append(entry.getValue().get(i));
|
||||
if (i < entry.getValue().size() - 1) {
|
||||
msg.append(", ");
|
||||
}
|
||||
}
|
||||
msg.append("\n");
|
||||
}
|
||||
logger.info(msg.toString());
|
||||
}
|
||||
|
||||
protected static class OutputStreamWrapper extends OutputStream {
|
||||
|
||||
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
private final OutputStream output;
|
||||
|
||||
private OutputStreamWrapper(OutputStream output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int i) throws IOException {
|
||||
buffer.write(i);
|
||||
output.write(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
buffer.write(b);
|
||||
output.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
buffer.write(b, off, len);
|
||||
output.write(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
output.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
output.close();
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
rest=com.alibaba.dubbo.rpc.protocol.rest.RestProtocol
|
||||
|
|
@ -40,5 +40,6 @@ limitations under the License.
|
|||
<module>dubbo-rpc-thrift</module>
|
||||
<module>dubbo-rpc-memcached</module>
|
||||
<module>dubbo-rpc-redis</module>
|
||||
<module>dubbo-rpc-rest</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -187,6 +187,53 @@ limitations under the License.
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo-rpc-rest</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxrs</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-client</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-netty</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jdk-http</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-undertow</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.undertow</groupId>
|
||||
<artifactId>undertow-servlet</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>io.undertow</groupId>
|
||||
<artifactId>undertow-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jackson-provider</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxb-provider</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>dubbo-registry-default</artifactId>
|
||||
|
|
|
|||
66
pom.xml
66
pom.xml
|
|
@ -113,6 +113,12 @@ limitations under the License.
|
|||
<cglib_version>2.2</cglib_version>
|
||||
<webx_version>3.1.6</webx_version>
|
||||
<velocity_version>1.7</velocity_version>
|
||||
<kryo_version>2.24.0</kryo_version>
|
||||
<kryo_serializers_version>0.26</kryo_serializers_version>
|
||||
<fst_version>1.55</fst_version>
|
||||
<rs_api_version>2.0</rs_api_version>
|
||||
<resteasy_version>3.0.7.Final</resteasy_version>
|
||||
<tomcat_embed_version>8.0.11</tomcat_embed_version>
|
||||
<!-- Log libs -->
|
||||
<slf4j_version>1.7.25</slf4j_version>
|
||||
<jcl_version>1.2</jcl_version>
|
||||
|
|
@ -303,6 +309,66 @@ limitations under the License.
|
|||
<artifactId>velocity</artifactId>
|
||||
<version>${velocity_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.esotericsoftware.kryo</groupId>
|
||||
<artifactId>kryo</artifactId>
|
||||
<version>${kryo_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.javakaffee</groupId>
|
||||
<artifactId>kryo-serializers</artifactId>
|
||||
<version>${kryo_serializers_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.ruedigermoeller</groupId>
|
||||
<artifactId>fst</artifactId>
|
||||
<version>${fst_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
<artifactId>javax.ws.rs-api</artifactId>
|
||||
<version>${rs_api_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxrs</artifactId>
|
||||
<version>${resteasy_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-client</artifactId>
|
||||
<version>${resteasy_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-netty</artifactId>
|
||||
<version>${resteasy_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jdk-http</artifactId>
|
||||
<version>${resteasy_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jackson-provider</artifactId>
|
||||
<version>${resteasy_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxb-provider</artifactId>
|
||||
<version>${resteasy_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-core</artifactId>
|
||||
<version>${tomcat_embed_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-logging-juli</artifactId>
|
||||
<version>${tomcat_embed_version}</version>
|
||||
</dependency>
|
||||
<!-- Log libs -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
|
|
|||
Loading…
Reference in New Issue