Compare commits
44 Commits
2.0.0.beta
...
2.0.0.beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c37b0e8cb5 | ||
|
|
a20570a6eb | ||
|
|
5e3edb7e1d | ||
|
|
ad8f1d2da6 | ||
|
|
24b23c894f | ||
|
|
c551d5fb81 | ||
|
|
fba43894c1 | ||
|
|
22cc7e086c | ||
|
|
1791008729 | ||
|
|
90e15dd253 | ||
|
|
7db73c076c | ||
|
|
95ad6e99d9 | ||
|
|
0b2a5d0f61 | ||
|
|
b7acce0814 | ||
|
|
8744e76cad | ||
|
|
446b3c13dc | ||
|
|
3951e28148 | ||
|
|
b74d679608 | ||
|
|
edbc878b73 | ||
|
|
f706209ec1 | ||
|
|
bf000b188f | ||
|
|
def1736a9b | ||
|
|
0242f4c0c3 | ||
|
|
5cd399b2df | ||
|
|
9ddb662016 | ||
|
|
2947275d54 | ||
|
|
e43f814872 | ||
|
|
6e16f52e28 | ||
|
|
fca13557df | ||
|
|
824a6df55a | ||
|
|
b98b526c50 | ||
|
|
8f6aa4f4a5 | ||
|
|
00a07a79b2 | ||
|
|
264dfbef2e | ||
|
|
2e27814809 | ||
|
|
f767f40e56 | ||
|
|
543ecc071a | ||
|
|
2a14f39495 | ||
|
|
95c8ae2334 | ||
|
|
338ea13828 | ||
|
|
4a8b9e5fec | ||
|
|
e281cac3d3 | ||
|
|
a495829a3c | ||
|
|
b0deed2a89 |
@@ -1,63 +0,0 @@
|
|||||||
/** *****************************************************************************
|
|
||||||
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
|
|
||||||
* which accompanies this distribution.
|
|
||||||
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
* and the Eclipse Distribution License is available at
|
|
||||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
|
||||||
*
|
|
||||||
* Contributors:
|
|
||||||
* Linda DeMichiel - Java Persistence 2.1
|
|
||||||
* Linda DeMichiel - Java Persistence 2.0
|
|
||||||
*
|
|
||||||
***************************************************************************** */
|
|
||||||
package javax.persistence;
|
|
||||||
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import static java.lang.annotation.ElementType.FIELD;
|
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides for the specification of generation strategies for the
|
|
||||||
* values of primary keys.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The <code>GeneratedValue</code> annotation
|
|
||||||
* may be applied to a primary key property or field of an entity or
|
|
||||||
* mapped superclass in conjunction with the {@link Id} annotation.
|
|
||||||
* The use of the <code>GeneratedValue</code> annotation is only
|
|
||||||
* required to be supported for simple primary keys. Use of the
|
|
||||||
* <code>GeneratedValue</code> annotation is not supported for derived
|
|
||||||
* primary keys.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
*
|
|
||||||
* Example 1:
|
|
||||||
*
|
|
||||||
* @Id
|
|
||||||
* @GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ")
|
|
||||||
* @Column(name="CUST_ID")
|
|
||||||
* public Long getId() { return id; }
|
|
||||||
*
|
|
||||||
* Example 2:
|
|
||||||
*
|
|
||||||
* @Id
|
|
||||||
* @GeneratedValue(strategy=TABLE, generator="CUST_GEN")
|
|
||||||
* @Column(name="CUST_ID")
|
|
||||||
* Long id;
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see Id
|
|
||||||
*
|
|
||||||
* @since Java Persistence 1.0
|
|
||||||
*/
|
|
||||||
@Target({METHOD, FIELD})
|
|
||||||
@Retention(RUNTIME)
|
|
||||||
|
|
||||||
public @interface GeneratedValue {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @see Column
|
* @see Column
|
||||||
* @see GeneratedValue
|
* see GeneratedValue
|
||||||
*
|
*
|
||||||
* @since Java Persistence 1.0
|
* @since Java Persistence 1.0
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ package org.redkale.convert;
|
|||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.*;
|
||||||
|
import org.redkale.util.Attribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化/反序列化操作类
|
* 序列化/反序列化操作类
|
||||||
@@ -31,6 +32,17 @@ public abstract class Convert<R extends Reader, W extends Writer> {
|
|||||||
return this.factory;
|
return this.factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected <S extends W> S configWrite(S writer) {
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> fieldFunc) {
|
||||||
|
writer.fieldFunc = fieldFunc;
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> fieldFunc);
|
||||||
|
|
||||||
public abstract boolean isBinary();
|
public abstract boolean isBinary();
|
||||||
|
|
||||||
public abstract <T> T convertFrom(final Type type, final byte[] bytes);
|
public abstract <T> T convertFrom(final Type type, final byte[] bytes);
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
|||||||
|
|
||||||
this.register(Number.class, NumberSimpledCoder.instance);
|
this.register(Number.class, NumberSimpledCoder.instance);
|
||||||
this.register(String.class, StringSimpledCoder.instance);
|
this.register(String.class, StringSimpledCoder.instance);
|
||||||
this.register(StringConvertWrapper.class, StringConvertWrapperSimpledCoder.instance);
|
this.register(StringWrapper.class, StringWrapperSimpledCoder.instance);
|
||||||
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
|
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
|
||||||
this.register(StringBuilder.class, CharSequenceSimpledCoder.StringBuilderSimpledCoder.instance);
|
this.register(StringBuilder.class, CharSequenceSimpledCoder.StringBuilderSimpledCoder.instance);
|
||||||
this.register(java.util.Date.class, DateSimpledCoder.instance);
|
this.register(java.util.Date.class, DateSimpledCoder.instance);
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
|
||||||
* To change this template file, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
package org.redkale.convert;
|
|
||||||
|
|
||||||
import org.redkale.convert.json.JsonConvert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 序列化去掉引号的String对象。
|
|
||||||
* <blockquote><pre>
|
|
||||||
* 场景: JavaBean bean = ... ;
|
|
||||||
* Map map = new HashMap();
|
|
||||||
* map.put("bean", a);
|
|
||||||
* records.add(map);
|
|
||||||
* records需要在后期序列化写入库。 但是在这期间bean的内部字段值可能就变化了,会导致入库时并不是records.add的快照信息。
|
|
||||||
* 所以需要使用StringConvertWrapper:
|
|
||||||
* Map map = new HashMap();
|
|
||||||
* map.put("bean", new StringConvertWrapper(bean.toString()));
|
|
||||||
* records.add(map);
|
|
||||||
* 这样既可以保持快照又不会在bean的值上面多一层引号。
|
|
||||||
* </pre></blockquote>
|
|
||||||
* <p>
|
|
||||||
* 详情见: https://redkale.org
|
|
||||||
*
|
|
||||||
* @author zhangjx
|
|
||||||
*/
|
|
||||||
public class StringConvertWrapper {
|
|
||||||
|
|
||||||
protected String value;
|
|
||||||
|
|
||||||
public StringConvertWrapper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringConvertWrapper(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StringConvertWrapper create(Object value) {
|
|
||||||
return create(JsonConvert.root(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StringConvertWrapper create(TextConvert convert, Object value) {
|
|
||||||
if (value == null) return new StringConvertWrapper(null);
|
|
||||||
if (value instanceof String) return new StringConvertWrapper((String) value);
|
|
||||||
return new StringConvertWrapper(convert.convertTo(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,8 @@
|
|||||||
package org.redkale.convert;
|
package org.redkale.convert;
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化的数据输出流
|
* 序列化的数据输出流
|
||||||
@@ -23,6 +25,9 @@ public abstract class Writer {
|
|||||||
//convertTo时是否以指定Type的ObjectEncoder进行处理
|
//convertTo时是否以指定Type的ObjectEncoder进行处理
|
||||||
protected Type specify;
|
protected Type specify;
|
||||||
|
|
||||||
|
//对某个字段值进行动态处理
|
||||||
|
protected BiFunction<Attribute, Object, Object> fieldFunc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置specify
|
* 设置specify
|
||||||
*
|
*
|
||||||
@@ -38,6 +43,11 @@ public abstract class Writer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean recycle() {
|
||||||
|
this.fieldFunc = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回specify
|
* 返回specify
|
||||||
*
|
*
|
||||||
@@ -105,7 +115,12 @@ public abstract class Writer {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void writeObjectField(final EnMember member, Object obj) {
|
public void writeObjectField(final EnMember member, Object obj) {
|
||||||
Object value = member.attribute.get(obj);
|
Object value;
|
||||||
|
if (fieldFunc == null) {
|
||||||
|
value = member.attribute.get(obj);
|
||||||
|
} else {
|
||||||
|
value = fieldFunc.apply(member.attribute, obj);
|
||||||
|
}
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
if (tiny()) {
|
if (tiny()) {
|
||||||
if (member.istring) {
|
if (member.istring) {
|
||||||
@@ -262,5 +277,5 @@ public abstract class Writer {
|
|||||||
*
|
*
|
||||||
* @param value StringConvertWrapper值
|
* @param value StringConvertWrapper值
|
||||||
*/
|
*/
|
||||||
public abstract void writeWrapper(StringConvertWrapper value);
|
public abstract void writeWrapper(StringWrapper value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ public class BsonByteBufferWriter extends BsonWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
this.buffers = null;
|
this.buffers = null;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import org.redkale.util.*;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||||
|
|
||||||
private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16));
|
private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16));
|
||||||
|
|
||||||
@@ -59,6 +59,16 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
return BsonFactory.root().getConvert();
|
return BsonFactory.root().getConvert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc) {
|
||||||
|
return new BsonConvert(getFactory(), tiny) {
|
||||||
|
@Override
|
||||||
|
protected <S extends BsonWriter> S configWrite(S writer) {
|
||||||
|
return fieldFunc(writer, fieldFunc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------ reader -----------------------------------------------------------
|
//------------------------------ reader -----------------------------------------------------------
|
||||||
public BsonReader pollBsonReader(final ByteBuffer... buffers) {
|
public BsonReader pollBsonReader(final ByteBuffer... buffers) {
|
||||||
return new BsonByteBufferReader((ConvertMask) null, buffers);
|
return new BsonByteBufferReader((ConvertMask) null, buffers);
|
||||||
@@ -78,11 +88,11 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
|
|
||||||
//------------------------------ writer -----------------------------------------------------------
|
//------------------------------ writer -----------------------------------------------------------
|
||||||
public BsonByteBufferWriter pollBsonWriter(final Supplier<ByteBuffer> supplier) {
|
public BsonByteBufferWriter pollBsonWriter(final Supplier<ByteBuffer> supplier) {
|
||||||
return new BsonByteBufferWriter(tiny, supplier);
|
return configWrite(new BsonByteBufferWriter(tiny, supplier));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BsonWriter pollBsonWriter(final OutputStream out) {
|
public BsonWriter pollBsonWriter(final OutputStream out) {
|
||||||
return new BsonStreamWriter(tiny, out);
|
return configWrite(new BsonStreamWriter(tiny, out));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BsonWriter pollBsonWriter() {
|
public BsonWriter pollBsonWriter() {
|
||||||
@@ -94,6 +104,7 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------ convertFrom -----------------------------------------------------------
|
//------------------------------ convertFrom -----------------------------------------------------------
|
||||||
|
@Override
|
||||||
public <T> T convertFrom(final Type type, final byte[] bytes) {
|
public <T> T convertFrom(final Type type, final byte[] bytes) {
|
||||||
if (bytes == null) return null;
|
if (bytes == null) return null;
|
||||||
return convertFrom(type, bytes, 0, bytes.length);
|
return convertFrom(type, bytes, 0, bytes.length);
|
||||||
@@ -173,33 +184,33 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
|
|
||||||
public void convertTo(final OutputStream out, final Object value) {
|
public void convertTo(final OutputStream out, final Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new BsonStreamWriter(tiny, out).writeNull();
|
pollBsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
factory.loadEncoder(value.getClass()).convertTo(new BsonStreamWriter(tiny, out), value);
|
factory.loadEncoder(value.getClass()).convertTo(pollBsonWriter(out), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
||||||
if (type == null) return;
|
if (type == null) return;
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new BsonStreamWriter(tiny, out).writeNull();
|
pollBsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
factory.loadEncoder(type).convertTo(new BsonStreamWriter(tiny, out), value);
|
factory.loadEncoder(type).convertTo(pollBsonWriter(out), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void convertMapTo(final OutputStream out, final Object... values) {
|
public void convertMapTo(final OutputStream out, final Object... values) {
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
new BsonStreamWriter(tiny, out).writeNull();
|
pollBsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(new BsonStreamWriter(tiny, out), values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(pollBsonWriter(out), values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
BsonByteBufferWriter out = pollBsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -211,7 +222,7 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
||||||
if (supplier == null || type == null) return null;
|
if (supplier == null || type == null) return null;
|
||||||
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
BsonByteBufferWriter out = pollBsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -223,7 +234,7 @@ public final class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
|
BsonByteBufferWriter out = pollBsonWriter(supplier);
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class BsonWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected BsonWriter(byte[] bs) {
|
protected BsonWriter(byte[] bs) {
|
||||||
this.content = bs;
|
this.content = bs == null ? new byte[0] : bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BsonWriter() {
|
public BsonWriter() {
|
||||||
@@ -97,10 +97,12 @@ public class BsonWriter extends Writer {
|
|||||||
count += len;
|
count += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
if (this.content.length > defaultSize) {
|
if (this.content != null && this.content.length > defaultSize) {
|
||||||
this.content = new byte[defaultSize];
|
this.content = new byte[defaultSize];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -242,7 +244,7 @@ public class BsonWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeWrapper(StringConvertWrapper value) {
|
public final void writeWrapper(StringWrapper value) {
|
||||||
this.writeString(value == null ? null : value.getValue());
|
this.writeString(value == null ? null : value.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import org.redkale.convert.*;
|
|||||||
*/
|
*/
|
||||||
public class FileSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, File> {
|
public class FileSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, File> {
|
||||||
|
|
||||||
public static final PatternSimpledCoder instance = new PatternSimpledCoder();
|
public static final FileSimpledCoder instance = new FileSimpledCoder();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void convertTo(W out, File value) {
|
public void convertTo(W out, File value) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.redkale.convert.ext;
|
package org.redkale.convert.ext;
|
||||||
|
|
||||||
import org.redkale.convert.*;
|
import org.redkale.convert.*;
|
||||||
|
import org.redkale.util.StringWrapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String 的SimpledCoder实现
|
* String 的SimpledCoder实现
|
||||||
@@ -17,18 +18,18 @@ import org.redkale.convert.*;
|
|||||||
* @param <R> Reader输入的子类型
|
* @param <R> Reader输入的子类型
|
||||||
* @param <W> Writer输出的子类型
|
* @param <W> Writer输出的子类型
|
||||||
*/
|
*/
|
||||||
public final class StringConvertWrapperSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, StringConvertWrapper> {
|
public final class StringWrapperSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, StringWrapper> {
|
||||||
|
|
||||||
public static final StringConvertWrapperSimpledCoder instance = new StringConvertWrapperSimpledCoder();
|
public static final StringWrapperSimpledCoder instance = new StringWrapperSimpledCoder();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void convertTo(W out, StringConvertWrapper value) {
|
public void convertTo(W out, StringWrapper value) {
|
||||||
out.writeWrapper(value);
|
out.writeWrapper(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StringConvertWrapper convertFrom(R in) {
|
public StringWrapper convertFrom(R in) {
|
||||||
return new StringConvertWrapper(in.readString());
|
return new StringWrapper(in.readString());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -48,6 +48,7 @@ public class JsonByteBufferWriter extends JsonWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
this.charset = null;
|
this.charset = null;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import org.redkale.util.*;
|
|||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||||
|
|
||||||
public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.HashMap<String, String>>() {
|
public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.HashMap<String, String>>() {
|
||||||
}.getType();
|
}.getType();
|
||||||
@@ -46,6 +46,16 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
return JsonFactory.root().getConvert();
|
return JsonFactory.root().getConvert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc) {
|
||||||
|
return new JsonConvert(getFactory(), tiny) {
|
||||||
|
@Override
|
||||||
|
protected <S extends JsonWriter> S configWrite(S writer) {
|
||||||
|
return fieldFunc(writer, fieldFunc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------ reader -----------------------------------------------------------
|
//------------------------------ reader -----------------------------------------------------------
|
||||||
public JsonReader pollJsonReader(final ByteBuffer... buffers) {
|
public JsonReader pollJsonReader(final ByteBuffer... buffers) {
|
||||||
return new JsonByteBufferReader((ConvertMask) null, buffers);
|
return new JsonByteBufferReader((ConvertMask) null, buffers);
|
||||||
@@ -65,19 +75,19 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
//------------------------------ writer -----------------------------------------------------------
|
//------------------------------ writer -----------------------------------------------------------
|
||||||
public JsonByteBufferWriter pollJsonWriter(final Supplier<ByteBuffer> supplier) {
|
public JsonByteBufferWriter pollJsonWriter(final Supplier<ByteBuffer> supplier) {
|
||||||
return new JsonByteBufferWriter(tiny, supplier);
|
return configWrite(new JsonByteBufferWriter(tiny, supplier));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter pollJsonWriter(final OutputStream out) {
|
public JsonWriter pollJsonWriter(final OutputStream out) {
|
||||||
return new JsonStreamWriter(tiny, out);
|
return configWrite(new JsonStreamWriter(tiny, out));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter pollJsonWriter(final Charset charset, final OutputStream out) {
|
public JsonWriter pollJsonWriter(final Charset charset, final OutputStream out) {
|
||||||
return new JsonStreamWriter(tiny, charset, out);
|
return configWrite(new JsonStreamWriter(tiny, charset, out));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter pollJsonWriter() {
|
public JsonWriter pollJsonWriter() {
|
||||||
return writerPool.get().tiny(tiny);
|
return configWrite(writerPool.get().tiny(tiny));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void offerJsonWriter(final JsonWriter writer) {
|
public void offerJsonWriter(final JsonWriter writer) {
|
||||||
@@ -85,6 +95,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------ convertFrom -----------------------------------------------------------
|
//------------------------------ convertFrom -----------------------------------------------------------
|
||||||
|
@Override
|
||||||
public <T> T convertFrom(final Type type, final byte[] bytes) {
|
public <T> T convertFrom(final Type type, final byte[] bytes) {
|
||||||
if (bytes == null) return null;
|
if (bytes == null) return null;
|
||||||
return convertFrom(type, new String(bytes, StandardCharsets.UTF_8));
|
return convertFrom(type, new String(bytes, StandardCharsets.UTF_8));
|
||||||
@@ -190,7 +201,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
public String convertTo(final Type type, final Object value) {
|
public String convertTo(final Type type, final Object value) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
if (value == null) return "null";
|
if (value == null) return "null";
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
writer.specify(type);
|
writer.specify(type);
|
||||||
factory.loadEncoder(type).convertTo(writer, value);
|
factory.loadEncoder(type).convertTo(writer, value);
|
||||||
String result = writer.toString();
|
String result = writer.toString();
|
||||||
@@ -201,7 +212,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public String convertMapTo(final Object... values) {
|
public String convertMapTo(final Object... values) {
|
||||||
if (values == null) return "null";
|
if (values == null) return "null";
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
||||||
String result = writer.toString();
|
String result = writer.toString();
|
||||||
writerPool.accept(writer);
|
writerPool.accept(writer);
|
||||||
@@ -210,7 +221,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
public void convertTo(final OutputStream out, final Object value) {
|
public void convertTo(final OutputStream out, final Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new JsonStreamWriter(tiny, out).writeNull();
|
pollJsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
convertTo(out, value.getClass(), value);
|
convertTo(out, value.getClass(), value);
|
||||||
}
|
}
|
||||||
@@ -219,9 +230,9 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
||||||
if (type == null) return;
|
if (type == null) return;
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
new JsonStreamWriter(tiny, out).writeNull();
|
pollJsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
writer.specify(type);
|
writer.specify(type);
|
||||||
factory.loadEncoder(type).convertTo(writer, value);
|
factory.loadEncoder(type).convertTo(writer, value);
|
||||||
byte[] bs = writer.toBytes();
|
byte[] bs = writer.toBytes();
|
||||||
@@ -236,9 +247,9 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
public void convertMapTo(final OutputStream out, final Object... values) {
|
public void convertMapTo(final OutputStream out, final Object... values) {
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
new JsonStreamWriter(tiny, out).writeNull();
|
pollJsonWriter(out).writeNull();
|
||||||
} else {
|
} else {
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
||||||
byte[] bs = writer.toBytes();
|
byte[] bs = writer.toBytes();
|
||||||
writerPool.accept(writer);
|
writerPool.accept(writer);
|
||||||
@@ -253,7 +264,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
JsonByteBufferWriter out = pollJsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -265,7 +276,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
||||||
if (supplier == null || type == null) return null;
|
if (supplier == null || type == null) return null;
|
||||||
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
JsonByteBufferWriter out = pollJsonWriter(supplier);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -278,7 +289,7 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
public ByteBuffer[] convertMapTo(final Supplier<ByteBuffer> supplier, final Object... values) {
|
||||||
if (supplier == null) return null;
|
if (supplier == null) return null;
|
||||||
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
|
JsonByteBufferWriter out = pollJsonWriter(supplier);
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
out.writeNull();
|
out.writeNull();
|
||||||
} else {
|
} else {
|
||||||
@@ -320,14 +331,14 @@ public final class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
|||||||
|
|
||||||
public JsonWriter convertToWriter(final Type type, final Object value) {
|
public JsonWriter convertToWriter(final Type type, final Object value) {
|
||||||
if (type == null) return null;
|
if (type == null) return null;
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
writer.specify(type);
|
writer.specify(type);
|
||||||
factory.loadEncoder(type).convertTo(writer, value);
|
factory.loadEncoder(type).convertTo(writer, value);
|
||||||
return writer;
|
return writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonWriter convertMapToWriter(final Object... values) {
|
public JsonWriter convertMapToWriter(final Object... values) {
|
||||||
final JsonWriter writer = writerPool.get().tiny(tiny);
|
final JsonWriter writer = pollJsonWriter();
|
||||||
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
((AnyEncoder) factory.getAnyEncoder()).convertMapTo(writer, values);
|
||||||
return writer;
|
return writer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,10 +97,12 @@ public class JsonWriter extends Writer {
|
|||||||
if (quote) content[count++] = '"';
|
if (quote) content[count++] = '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected boolean recycle() {
|
protected boolean recycle() {
|
||||||
|
super.recycle();
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
this.specify = null;
|
this.specify = null;
|
||||||
if (this.content.length > defaultSize) {
|
if (this.content != null && this.content.length > defaultSize) {
|
||||||
this.content = new char[defaultSize];
|
this.content = new char[defaultSize];
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -320,7 +322,7 @@ public class JsonWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeWrapper(StringConvertWrapper value) {
|
public final void writeWrapper(StringWrapper value) {
|
||||||
writeTo(false, String.valueOf(value));
|
writeTo(false, String.valueOf(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -283,11 +283,15 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
|
|||||||
serverChannel.bind(address, backlog);
|
serverChannel.bind(address, backlog);
|
||||||
serverChannel.accept(this);
|
serverChannel.accept(this);
|
||||||
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
final String threadName = "[" + Thread.currentThread().getName() + "] ";
|
||||||
|
postStart();
|
||||||
logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(protocol) ? "" : ("." + protocol)) + " listen: " + address
|
logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(protocol) ? "" : ("." + protocol)) + " listen: " + address
|
||||||
+ ", threads: " + threads + ", maxbody: " + formatLenth(context.maxbody) + ", bufferCapacity: " + formatLenth(bufferCapacity) + ", bufferPoolSize: " + bufferPoolSize + ", responsePoolSize: " + responsePoolSize
|
+ ", threads: " + threads + ", maxbody: " + formatLenth(context.maxbody) + ", bufferCapacity: " + formatLenth(bufferCapacity) + ", bufferPoolSize: " + bufferPoolSize + ", responsePoolSize: " + responsePoolSize
|
||||||
+ ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms");
|
+ ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void postStart() {
|
||||||
|
}
|
||||||
|
|
||||||
public void changeAddress(final InetSocketAddress addr) throws IOException {
|
public void changeAddress(final InetSocketAddress addr) throws IOException {
|
||||||
long s = System.currentTimeMillis();
|
long s = System.currentTimeMillis();
|
||||||
Objects.requireNonNull(addr);
|
Objects.requireNonNull(addr);
|
||||||
|
|||||||
@@ -23,11 +23,13 @@ public abstract class Servlet<C extends Context, R extends Request<C>, P extends
|
|||||||
|
|
||||||
AnyValue _conf; //当前Servlet的配置
|
AnyValue _conf; //当前Servlet的配置
|
||||||
|
|
||||||
|
//Server执行start时运行此方法
|
||||||
public void init(C context, AnyValue config) {
|
public void init(C context, AnyValue config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void execute(R request, P response) throws IOException;
|
public abstract void execute(R request, P response) throws IOException;
|
||||||
|
|
||||||
|
//Server执行shutdown后运行此方法
|
||||||
public void destroy(C context, AnyValue config) {
|
public void destroy(C context, AnyValue config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.redkale.net.http;
|
package org.redkale.net.http;
|
||||||
|
|
||||||
import org.redkale.net.Filter;
|
import org.redkale.net.Filter;
|
||||||
|
import org.redkale.util.AnyValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP 过滤器 <br>
|
* HTTP 过滤器 <br>
|
||||||
@@ -17,4 +18,7 @@ import org.redkale.net.Filter;
|
|||||||
*/
|
*/
|
||||||
public abstract class HttpFilter extends Filter<HttpContext, HttpRequest, HttpResponse> {
|
public abstract class HttpFilter extends Filter<HttpContext, HttpRequest, HttpResponse> {
|
||||||
|
|
||||||
|
//Server执行start后运行此方法
|
||||||
|
public void postStart(HttpContext context, AnyValue config) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -402,6 +402,21 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
|
|||||||
return this.resourceHttpServlet;
|
return this.resourceHttpServlet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void postStart(HttpContext context, AnyValue config) {
|
||||||
|
List filters = getFilters();
|
||||||
|
synchronized (filters) {
|
||||||
|
if (!filters.isEmpty()) {
|
||||||
|
for (Object filter : filters) {
|
||||||
|
((HttpFilter) filter).postStart(context, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.resourceHttpServlet.postStart(context, config);
|
||||||
|
getServlets().forEach(s -> {
|
||||||
|
s.postStart(context, getServletConf(s));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy(HttpContext context, AnyValue config) {
|
public void destroy(HttpContext context, AnyValue config) {
|
||||||
super.destroy(context, config); //必须要执行
|
super.destroy(context, config); //必须要执行
|
||||||
|
|||||||
@@ -210,7 +210,9 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
|
|
||||||
private void parseBody() {
|
private void parseBody() {
|
||||||
if (this.boundary || bodyparsed) return;
|
if (this.boundary || bodyparsed) return;
|
||||||
addParameter(array, 0, array.size());
|
if (this.contentType != null && this.contentType.toLowerCase().contains("x-www-form-urlencoded")) {
|
||||||
|
addParameter(array, 0, array.size());
|
||||||
|
}
|
||||||
bodyparsed = true;
|
bodyparsed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1300,16 +1302,11 @@ public class HttpRequest extends Request<HttpContext> {
|
|||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
public String getParametersToString(String prefix) {
|
public String getParametersToString(String prefix) {
|
||||||
final StringBuilder sb = new StringBuilder();
|
byte[] rbs = queryBytes;
|
||||||
getParameters().forEach((k, v) -> {
|
if (rbs == null || rbs.length < 1) return "";
|
||||||
if (sb.length() > 0) sb.append('&');
|
Charset charset = this.context.getCharset();
|
||||||
try {
|
String str = charset == null ? new String(rbs, StandardCharsets.UTF_8) : new String(rbs, charset);
|
||||||
sb.append(k).append('=').append(URLEncoder.encode(v, "UTF-8"));
|
return (prefix == null) ? str : (prefix + str);
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return (sb.length() > 0 && prefix != null) ? (prefix + sb) : sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -390,7 +390,9 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
this.header.addValue("retcode", String.valueOf(ret.getRetcode()));
|
this.header.addValue("retcode", String.valueOf(ret.getRetcode()));
|
||||||
this.header.addValue("retinfo", ret.getRetinfo());
|
this.header.addValue("retinfo", ret.getRetinfo());
|
||||||
}
|
}
|
||||||
finish(request.getJsonConvert().convertTo(getBodyBufferSupplier(), ret));
|
Convert convert = ret == null ? null : ret.convert();
|
||||||
|
if (convert == null || !(convert instanceof TextConvert)) convert = request.getJsonConvert();
|
||||||
|
finish(convert.convertTo(getBodyBufferSupplier(), ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -497,6 +499,8 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
context.getLogger().log(Level.WARNING, "HttpServlet finish File occur, force to close channel. request = " + getRequest(), e);
|
context.getLogger().log(Level.WARNING, "HttpServlet finish File occur, force to close channel. request = " + getRequest(), e);
|
||||||
finish(500, null);
|
finish(500, null);
|
||||||
}
|
}
|
||||||
|
} else if (obj instanceof org.redkale.service.RetResult) {
|
||||||
|
finishJson((org.redkale.service.RetResult) obj);
|
||||||
} else if (obj instanceof HttpResult) {
|
} else if (obj instanceof HttpResult) {
|
||||||
HttpResult result = (HttpResult) obj;
|
HttpResult result = (HttpResult) obj;
|
||||||
if (result.getContentType() != null) setContentType(result.getContentType());
|
if (result.getContentType() != null) setContentType(result.getContentType());
|
||||||
@@ -506,7 +510,9 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
|||||||
} else if (result.getResult() instanceof CharSequence) {
|
} else if (result.getResult() instanceof CharSequence) {
|
||||||
finish(result.getResult().toString());
|
finish(result.getResult().toString());
|
||||||
} else {
|
} else {
|
||||||
finish(convert, result.getResult());
|
Convert cc = result.convert();
|
||||||
|
if (cc == null || !(cc instanceof TextConvert)) cc = convert;
|
||||||
|
finish(cc, result.getResult());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (hasRender) {
|
if (hasRender) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package org.redkale.net.http;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.net.HttpCookie;
|
import java.net.HttpCookie;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import org.redkale.convert.*;
|
||||||
import org.redkale.convert.json.JsonConvert;
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,21 +23,28 @@ public class HttpResult<T> {
|
|||||||
|
|
||||||
public static final String SESSIONID_COOKIENAME = HttpRequest.SESSIONID_NAME;
|
public static final String SESSIONID_COOKIENAME = HttpRequest.SESSIONID_NAME;
|
||||||
|
|
||||||
private Map<String, String> headers;
|
protected Map<String, String> headers;
|
||||||
|
|
||||||
private List<HttpCookie> cookies;
|
protected List<HttpCookie> cookies;
|
||||||
|
|
||||||
private String contentType;
|
protected String contentType;
|
||||||
|
|
||||||
private T result;
|
protected T result;
|
||||||
|
|
||||||
private int status = 0; //不设置则为 200
|
protected int status = 0; //不设置则为 200
|
||||||
|
|
||||||
private String message;
|
protected String message;
|
||||||
|
|
||||||
|
protected Convert convert;
|
||||||
|
|
||||||
public HttpResult() {
|
public HttpResult() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HttpResult(Convert convert, T result) {
|
||||||
|
this.convert = convert;
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
public HttpResult(T result) {
|
public HttpResult(T result) {
|
||||||
this.result = result;
|
this.result = result;
|
||||||
}
|
}
|
||||||
@@ -82,6 +90,14 @@ public class HttpResult<T> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Convert convert() {
|
||||||
|
return convert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void convert(Convert convert) {
|
||||||
|
this.convert = convert;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, String> getHeaders() {
|
public Map<String, String> getHeaders() {
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ public class HttpServer extends Server<String, HttpContext, HttpRequest, HttpRes
|
|||||||
super.init(config);
|
super.init(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void postStart() {
|
||||||
|
((HttpPrepareServlet) this.prepare).postStart(this.context, config);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy(final AnyValue config) throws Exception {
|
public void destroy(final AnyValue config) throws Exception {
|
||||||
super.destroy(config);
|
super.destroy(config);
|
||||||
|
|||||||
@@ -105,6 +105,10 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
|
|||||||
void postDestroy(HttpContext context, AnyValue config) {
|
void postDestroy(HttpContext context, AnyValue config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Server执行start后运行此方法
|
||||||
|
public void postStart(HttpContext context, AnyValue config) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* 预执行方法,在execute方法之前运行,设置当前用户信息,或者加入常规统计和基础检测,例如 : <br>
|
* 预执行方法,在execute方法之前运行,设置当前用户信息,或者加入常规统计和基础检测,例如 : <br>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.lang.annotation.*;
|
|||||||
import static java.lang.annotation.ElementType.*;
|
import static java.lang.annotation.ElementType.*;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.channels.CompletionHandler;
|
import java.nio.channels.CompletionHandler;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -859,7 +860,7 @@ public final class Rest {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (defmodulename.isEmpty() || (!pound && entrys.size() <= 6)) {
|
if (defmodulename.isEmpty() || (!pound && entrys.size() <= 2)) {
|
||||||
for (MappingEntry entry : entrys) {
|
for (MappingEntry entry : entrys) {
|
||||||
String suburl = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + (defmodulename.isEmpty() ? "" : (defmodulename + "/")) + entry.name;
|
String suburl = (catalog.isEmpty() ? "/" : ("/" + catalog + "/")) + (defmodulename.isEmpty() ? "" : (defmodulename + "/")) + entry.name;
|
||||||
urlpath += "," + suburl;
|
urlpath += "," + suburl;
|
||||||
@@ -1002,7 +1003,7 @@ public final class Rest {
|
|||||||
|
|
||||||
RestHeader annhead = param.getAnnotation(RestHeader.class);
|
RestHeader annhead = param.getAnnotation(RestHeader.class);
|
||||||
if (annhead != null) {
|
if (annhead != null) {
|
||||||
if (ptype != String.class) throw new RuntimeException("@RestHeader must on String Parameter in " + method);
|
if (ptype != String.class && ptype != InetSocketAddress.class) throw new RuntimeException("@RestHeader must on String or InetSocketAddress Parameter in " + method);
|
||||||
n = annhead.name();
|
n = annhead.name();
|
||||||
radix = annhead.radix();
|
radix = annhead.radix();
|
||||||
comment = annhead.comment();
|
comment = annhead.comment();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import static java.lang.annotation.ElementType.*;
|
|||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 只能注解于RestService类的方法的参数或参数内的String字段
|
* 只能注解于RestService类的方法的参数或参数内的String、java.net.InetSocketAddress字段
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ public abstract class WebSocket<G extends Serializable, T> {
|
|||||||
|
|
||||||
WebSocketEngine _engine; //不可能为空
|
WebSocketEngine _engine; //不可能为空
|
||||||
|
|
||||||
|
InetSocketAddress _sncpAddress; //分布式下不可为空
|
||||||
|
|
||||||
AsyncConnection _channel;//不可能为空
|
AsyncConnection _channel;//不可能为空
|
||||||
|
|
||||||
String _sessionid; //不可能为空
|
String _sessionid; //不可能为空
|
||||||
@@ -826,6 +828,15 @@ public abstract class WebSocket<G extends Serializable, T> {
|
|||||||
return forceCloseWebSocket(getUserid()).thenApply((r) -> true);
|
return forceCloseWebSocket(getUserid()).thenApply((r) -> true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取分布式情况下的SNCP地址, 非分布式下为null
|
||||||
|
*
|
||||||
|
* @return InetSocketAddress sncpAddress
|
||||||
|
*/
|
||||||
|
public InetSocketAddress getSncpAddress() {
|
||||||
|
return _sncpAddress;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Logger
|
* 获取Logger
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ public abstract class WebSocketNode {
|
|||||||
*/
|
*/
|
||||||
@Local
|
@Local
|
||||||
public CompletableFuture<Boolean> existsWebSocket(final Serializable userid) {
|
public CompletableFuture<Boolean> existsWebSocket(final Serializable userid) {
|
||||||
|
if (userid instanceof WebSocketUserAddress) return existsWebSocket((WebSocketUserAddress) userid);
|
||||||
CompletableFuture<Boolean> localFuture = null;
|
CompletableFuture<Boolean> localFuture = null;
|
||||||
if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid));
|
if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid));
|
||||||
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
|
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
|
||||||
@@ -229,7 +230,7 @@ public abstract class WebSocketNode {
|
|||||||
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
|
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
|
||||||
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
||||||
CompletableFuture<Boolean> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
|
CompletableFuture<Boolean> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
|
||||||
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs);
|
//if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs);
|
||||||
if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(false);
|
if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(false);
|
||||||
CompletableFuture<Boolean> future = null;
|
CompletableFuture<Boolean> future = null;
|
||||||
for (InetSocketAddress addr : addrs) {
|
for (InetSocketAddress addr : addrs) {
|
||||||
@@ -242,6 +243,38 @@ public abstract class WebSocketNode {
|
|||||||
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
|
return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断指定用户是否WebSocket在线
|
||||||
|
*
|
||||||
|
* @param userAddress WebSocketUserAddress
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
@Local
|
||||||
|
public CompletableFuture<Boolean> existsWebSocket(final WebSocketUserAddress userAddress) {
|
||||||
|
CompletableFuture<Boolean> localFuture = null;
|
||||||
|
if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userAddress.userid()));
|
||||||
|
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
|
||||||
|
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
|
||||||
|
//没有CacheSource就不会有分布式节点
|
||||||
|
return localFuture;
|
||||||
|
}
|
||||||
|
Collection<InetSocketAddress> addrs = userAddress.sncpAddresses();
|
||||||
|
if (addrs != null) addrs = new ArrayList<>(addrs); //不能修改参数内部值
|
||||||
|
if (userAddress.sncpAddress() != null) {
|
||||||
|
if (addrs == null) addrs = new ArrayList<>();
|
||||||
|
addrs.add(userAddress.sncpAddress());
|
||||||
|
}
|
||||||
|
if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(false);
|
||||||
|
CompletableFuture<Boolean> future = null;
|
||||||
|
for (InetSocketAddress addr : addrs) {
|
||||||
|
if (addr == null || addr.equals(localSncpAddress)) continue;
|
||||||
|
future = future == null ? remoteNode.existsWebSocket(userAddress.userid(), addr)
|
||||||
|
: future.thenCombine(remoteNode.existsWebSocket(userAddress.userid(), addr), (a, b) -> a | b);
|
||||||
|
}
|
||||||
|
return future == null ? CompletableFuture.completedFuture(false) : future;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 强制关闭用户WebSocket
|
* 强制关闭用户WebSocket
|
||||||
*
|
*
|
||||||
@@ -251,17 +284,45 @@ public abstract class WebSocketNode {
|
|||||||
*/
|
*/
|
||||||
@Local
|
@Local
|
||||||
public CompletableFuture<Integer> forceCloseWebSocket(final Serializable userid) {
|
public CompletableFuture<Integer> forceCloseWebSocket(final Serializable userid) {
|
||||||
|
return forceCloseWebSocket(userid, (WebSocketUserAddress) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制关闭用户WebSocket
|
||||||
|
*
|
||||||
|
* @param userAddress WebSocketUserAddress
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
@Local
|
||||||
|
public CompletableFuture<Integer> forceCloseWebSocket(final WebSocketUserAddress userAddress) {
|
||||||
|
return forceCloseWebSocket(null, userAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Integer> forceCloseWebSocket(final Serializable userid, final WebSocketUserAddress userAddress) {
|
||||||
CompletableFuture<Integer> localFuture = null;
|
CompletableFuture<Integer> localFuture = null;
|
||||||
if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userid));
|
if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userAddress == null ? userid : userAddress.userid()));
|
||||||
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
|
if (this.sncpNodeAddresses == null || this.remoteNode == null) {
|
||||||
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
|
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket remote node is null");
|
||||||
//没有CacheSource就不会有分布式节点
|
//没有CacheSource就不会有分布式节点
|
||||||
return localFuture;
|
return localFuture;
|
||||||
}
|
}
|
||||||
//远程节点关闭
|
//远程节点关闭
|
||||||
tryAcquireSemaphore();
|
CompletableFuture<Collection<InetSocketAddress>> addrsFuture;
|
||||||
CompletableFuture<Collection<InetSocketAddress>> addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
|
if (userAddress == null) {
|
||||||
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
tryAcquireSemaphore();
|
||||||
|
addrsFuture = sncpNodeAddresses.getCollectionAsync(SOURCE_SNCP_USERID_PREFIX + userid, InetSocketAddress.class);
|
||||||
|
if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore());
|
||||||
|
} else {
|
||||||
|
Collection<InetSocketAddress> addrs = userAddress.sncpAddresses();
|
||||||
|
if (addrs != null) addrs = new ArrayList<>(addrs); //不能修改参数内部值
|
||||||
|
if (userAddress.sncpAddress() != null) {
|
||||||
|
if (addrs == null) addrs = new ArrayList<>();
|
||||||
|
addrs.add(userAddress.sncpAddress());
|
||||||
|
}
|
||||||
|
if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0);
|
||||||
|
addrsFuture = CompletableFuture.completedFuture(addrs);
|
||||||
|
}
|
||||||
CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
|
CompletableFuture<Integer> remoteFuture = addrsFuture.thenCompose((Collection<InetSocketAddress> addrs) -> {
|
||||||
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs);
|
if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs);
|
||||||
if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0);
|
if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0);
|
||||||
@@ -292,88 +353,88 @@ public abstract class WebSocketNode {
|
|||||||
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
||||||
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
||||||
*
|
*
|
||||||
* @param message 消息内容
|
* @param message 消息内容
|
||||||
* @param userids Stream
|
* @param useridOrAddrs Stream
|
||||||
*
|
*
|
||||||
* @return 为0表示成功, 其他值表示部分发送异常
|
* @return 为0表示成功, 其他值表示部分发送异常
|
||||||
*/
|
*/
|
||||||
@Local
|
@Local
|
||||||
public final CompletableFuture<Integer> sendMessage(Object message, final Stream<? extends Serializable> userids) {
|
public final CompletableFuture<Integer> sendMessage(Object message, final Stream<? extends Serializable> useridOrAddrs) {
|
||||||
return sendMessage((Convert) null, message, true, userids);
|
return sendMessage((Convert) null, message, true, useridOrAddrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
||||||
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
||||||
*
|
*
|
||||||
* @param message 消息内容
|
* @param message 消息内容
|
||||||
* @param userids Serializable[]
|
* @param useridOrAddrs Serializable[]
|
||||||
*
|
*
|
||||||
* @return 为0表示成功, 其他值表示部分发送异常
|
* @return 为0表示成功, 其他值表示部分发送异常
|
||||||
*/
|
*/
|
||||||
@Local
|
@Local
|
||||||
public final CompletableFuture<Integer> sendMessage(Object message, final Serializable... userids) {
|
public final CompletableFuture<Integer> sendMessage(Object message, final Serializable... useridOrAddrs) {
|
||||||
return sendMessage((Convert) null, message, true, userids);
|
return sendMessage((Convert) null, message, true, useridOrAddrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
||||||
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
||||||
*
|
*
|
||||||
* @param convert Convert
|
* @param convert Convert
|
||||||
* @param message 消息内容
|
* @param message 消息内容
|
||||||
* @param userids Stream
|
* @param useridOrAddrs Stream
|
||||||
*
|
*
|
||||||
* @return 为0表示成功, 其他值表示部分发送异常
|
* @return 为0表示成功, 其他值表示部分发送异常
|
||||||
*/
|
*/
|
||||||
@Local
|
@Local
|
||||||
public final CompletableFuture<Integer> sendMessage(final Convert convert, Object message, final Stream<? extends Serializable> userids) {
|
public final CompletableFuture<Integer> sendMessage(final Convert convert, Object message, final Stream<? extends Serializable> useridOrAddrs) {
|
||||||
return sendMessage(convert, message, true, userids);
|
return sendMessage(convert, message, true, useridOrAddrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
||||||
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
||||||
*
|
*
|
||||||
* @param convert Convert
|
* @param convert Convert
|
||||||
* @param message 消息内容
|
* @param message 消息内容
|
||||||
* @param userids Serializable[]
|
* @param useridOrAddrs Serializable[]
|
||||||
*
|
*
|
||||||
* @return 为0表示成功, 其他值表示部分发送异常
|
* @return 为0表示成功, 其他值表示部分发送异常
|
||||||
*/
|
*/
|
||||||
@Local
|
@Local
|
||||||
public final CompletableFuture<Integer> sendMessage(final Convert convert, Object message, final Serializable... userids) {
|
public final CompletableFuture<Integer> sendMessage(final Convert convert, Object message, final Serializable... useridOrAddrs) {
|
||||||
return sendMessage(convert, message, true, userids);
|
return sendMessage(convert, message, true, useridOrAddrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
||||||
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
||||||
*
|
*
|
||||||
* @param message 消息内容
|
* @param message 消息内容
|
||||||
* @param last 是否最后一条
|
* @param last 是否最后一条
|
||||||
* @param userids Stream
|
* @param useridOrAddrs Stream
|
||||||
*
|
*
|
||||||
* @return 为0表示成功, 其他值表示部分发送异常
|
* @return 为0表示成功, 其他值表示部分发送异常
|
||||||
*/
|
*/
|
||||||
@Local
|
@Local
|
||||||
public final CompletableFuture<Integer> sendMessage(final Object message, final boolean last, final Stream<? extends Serializable> userids) {
|
public final CompletableFuture<Integer> sendMessage(final Object message, final boolean last, final Stream<? extends Serializable> useridOrAddrs) {
|
||||||
return sendMessage((Convert) null, message, last, userids);
|
return sendMessage((Convert) null, message, last, useridOrAddrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
||||||
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
||||||
*
|
*
|
||||||
* @param message 消息内容
|
* @param message 消息内容
|
||||||
* @param last 是否最后一条
|
* @param last 是否最后一条
|
||||||
* @param userids Serializable[]
|
* @param useridOrAddrs Serializable[]
|
||||||
*
|
*
|
||||||
* @return 为0表示成功, 其他值表示部分发送异常
|
* @return 为0表示成功, 其他值表示部分发送异常
|
||||||
*/
|
*/
|
||||||
@Local
|
@Local
|
||||||
public final CompletableFuture<Integer> sendMessage(final Object message, final boolean last, final Serializable... userids) {
|
public final CompletableFuture<Integer> sendMessage(final Object message, final boolean last, final Serializable... useridOrAddrs) {
|
||||||
return sendMessage((Convert) null, message, last, userids);
|
return sendMessage((Convert) null, message, last, useridOrAddrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -411,6 +472,13 @@ public abstract class WebSocketNode {
|
|||||||
@Local
|
@Local
|
||||||
public CompletableFuture<Integer> sendMessage(final Convert convert, final Object message0, final boolean last, final Serializable... userids) {
|
public CompletableFuture<Integer> sendMessage(final Convert convert, final Object message0, final boolean last, final Serializable... userids) {
|
||||||
if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
||||||
|
if (userids[0] instanceof WebSocketUserAddress) {
|
||||||
|
WebSocketUserAddress[] useraddrs = new WebSocketUserAddress[userids.length];
|
||||||
|
for (int i = 0; i < useraddrs.length; i++) {
|
||||||
|
useraddrs[i] = (WebSocketUserAddress) userids[i];
|
||||||
|
}
|
||||||
|
return sendMessage(convert, message0, last, useraddrs);
|
||||||
|
}
|
||||||
if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, userids));
|
if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, userids));
|
||||||
final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), last));
|
final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), last));
|
||||||
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
||||||
@@ -446,9 +514,9 @@ public abstract class WebSocketNode {
|
|||||||
}
|
}
|
||||||
CompletableFuture<Integer> future = null;
|
CompletableFuture<Integer> future = null;
|
||||||
for (Map.Entry<InetSocketAddress, List<Serializable>> en : addrUsers.entrySet()) {
|
for (Map.Entry<InetSocketAddress, List<Serializable>> en : addrUsers.entrySet()) {
|
||||||
Serializable[] us = en.getValue().toArray(new Serializable[en.getValue().size()]);
|
Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]);
|
||||||
future = future == null ? sendOneAddrMessage(en.getKey(), remoteMessage, last, us)
|
future = future == null ? sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids)
|
||||||
: future.thenCombine(sendOneAddrMessage(en.getKey(), remoteMessage, last, us), (a, b) -> a | b);
|
: future.thenCombine(sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids), (a, b) -> a | b);
|
||||||
}
|
}
|
||||||
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
||||||
});
|
});
|
||||||
@@ -456,10 +524,45 @@ public abstract class WebSocketNode {
|
|||||||
return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture;
|
return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向指定用户发送消息,先发送本地连接,再发送远程连接 <br>
|
||||||
|
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
||||||
|
*
|
||||||
|
* @param convert Convert
|
||||||
|
* @param message0 消息内容
|
||||||
|
* @param last 是否最后一条
|
||||||
|
* @param useraddrs WebSocketUserAddress[]
|
||||||
|
*
|
||||||
|
* @return 为0表示成功, 其他值表示部分发送异常
|
||||||
|
*/
|
||||||
|
@Local
|
||||||
|
public CompletableFuture<Integer> sendMessage(final Convert convert, final Object message0, final boolean last, final WebSocketUserAddress... useraddrs) {
|
||||||
|
if (useraddrs == null || useraddrs.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
||||||
|
if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, useraddrs));
|
||||||
|
final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), last));
|
||||||
|
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
||||||
|
return this.localEngine.sendLocalMessage(message, last, userAddressToUserids(useraddrs));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object remoteMessage = formatRemoteMessage(message);
|
||||||
|
final Map<InetSocketAddress, List<Serializable>> addrUsers = userAddressToAddrMap(useraddrs);
|
||||||
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
|
logger.finest("websocket(localaddr=" + localSncpAddress + ", useraddrs=" + JsonConvert.root().convertTo(useraddrs) + ") found message-addr-userids: " + addrUsers);
|
||||||
|
}
|
||||||
|
CompletableFuture<Integer> future = null;
|
||||||
|
for (Map.Entry<InetSocketAddress, List<Serializable>> en : addrUsers.entrySet()) {
|
||||||
|
Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]);
|
||||||
|
future = future == null ? sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids)
|
||||||
|
: future.thenCombine(sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids), (a, b) -> a | b);
|
||||||
|
}
|
||||||
|
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected CompletableFuture<Integer> sendOneUserMessage(final Object message, final boolean last, final Serializable userid) {
|
protected CompletableFuture<Integer> sendOneUserMessage(final Object message, final boolean last, final Serializable userid) {
|
||||||
if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneUserMessage(msg, last, userid));
|
if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneUserMessage(msg, last, userid));
|
||||||
if (logger.isLoggable(Level.FINEST)) {
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
logger.finest("websocket want send message {userid:" + userid + ", content:'" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : JsonConvert.root().convertTo(message)) + "'} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
logger.finest("websocket want send message {userid:" + userid + ", content:" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : (message instanceof CharSequence ? message : JsonConvert.root().convertTo(message))) + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
||||||
}
|
}
|
||||||
CompletableFuture<Integer> localFuture = null;
|
CompletableFuture<Integer> localFuture = null;
|
||||||
if (this.localEngine != null) localFuture = localEngine.sendLocalMessage(message, last, userid);
|
if (this.localEngine != null) localFuture = localEngine.sendLocalMessage(message, last, userid);
|
||||||
@@ -493,7 +596,7 @@ public abstract class WebSocketNode {
|
|||||||
protected CompletableFuture<Integer> sendOneAddrMessage(final InetSocketAddress sncpAddr, final Object message, final boolean last, final Serializable... userids) {
|
protected CompletableFuture<Integer> sendOneAddrMessage(final InetSocketAddress sncpAddr, final Object message, final boolean last, final Serializable... userids) {
|
||||||
if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneAddrMessage(sncpAddr, msg, last, userids));
|
if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneAddrMessage(sncpAddr, msg, last, userids));
|
||||||
if (logger.isLoggable(Level.FINEST)) {
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
logger.finest("websocket want send message {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + sncpAddr + ", content:'" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : JsonConvert.root().convertTo(message)) + "'} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
logger.finest("websocket want send message {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + sncpAddr + ", content:" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : (message instanceof CharSequence ? message : JsonConvert.root().convertTo(message))) + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
||||||
}
|
}
|
||||||
if (Objects.equals(sncpAddr, this.localSncpAddress)) {
|
if (Objects.equals(sncpAddr, this.localSncpAddress)) {
|
||||||
return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalMessage(message, last, userids);
|
return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalMessage(message, last, userids);
|
||||||
@@ -507,6 +610,32 @@ public abstract class WebSocketNode {
|
|||||||
return remoteNode.sendMessage(sncpAddr, remoteMessage, last, userids);
|
return remoteNode.sendMessage(sncpAddr, remoteMessage, last, userids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Serializable[] userAddressToUserids(WebSocketUserAddress... useraddrs) {
|
||||||
|
if (useraddrs == null || useraddrs.length == 1) return new Serializable[0];
|
||||||
|
Set<Serializable> set = new HashSet<>();
|
||||||
|
for (WebSocketUserAddress userAddress : useraddrs) {
|
||||||
|
set.add(userAddress.userid());
|
||||||
|
}
|
||||||
|
return set.toArray(new Serializable[set.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<InetSocketAddress, List<Serializable>> userAddressToAddrMap(WebSocketUserAddress... useraddrs) {
|
||||||
|
final Map<InetSocketAddress, List<Serializable>> addrUsers = new HashMap<>();
|
||||||
|
for (WebSocketUserAddress userAddress : useraddrs) {
|
||||||
|
if (userAddress.sncpAddress() != null) {
|
||||||
|
addrUsers.computeIfAbsent(userAddress.sncpAddress(), k -> new ArrayList<>()).add(userAddress.userid());
|
||||||
|
}
|
||||||
|
if (userAddress.sncpAddresses() != null) {
|
||||||
|
for (InetSocketAddress addr : userAddress.sncpAddresses()) {
|
||||||
|
if (addr != null) {
|
||||||
|
addrUsers.computeIfAbsent(addr, k -> new ArrayList<>()).add(userAddress.userid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addrUsers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 广播消息, 给所有人发消息
|
* 广播消息, 给所有人发消息
|
||||||
*
|
*
|
||||||
@@ -678,6 +807,13 @@ public abstract class WebSocketNode {
|
|||||||
@Local
|
@Local
|
||||||
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final Serializable... userids) {
|
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final Serializable... userids) {
|
||||||
if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
||||||
|
if (userids[0] instanceof WebSocketUserAddress) {
|
||||||
|
WebSocketUserAddress[] useraddrs = new WebSocketUserAddress[userids.length];
|
||||||
|
for (int i = 0; i < useraddrs.length; i++) {
|
||||||
|
useraddrs[i] = (WebSocketUserAddress) userids[i];
|
||||||
|
}
|
||||||
|
return sendAction(action, useraddrs);
|
||||||
|
}
|
||||||
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
||||||
return this.localEngine.sendLocalAction(action, userids);
|
return this.localEngine.sendLocalAction(action, userids);
|
||||||
}
|
}
|
||||||
@@ -710,9 +846,9 @@ public abstract class WebSocketNode {
|
|||||||
}
|
}
|
||||||
CompletableFuture<Integer> future = null;
|
CompletableFuture<Integer> future = null;
|
||||||
for (Map.Entry<InetSocketAddress, List<Serializable>> en : addrUsers.entrySet()) {
|
for (Map.Entry<InetSocketAddress, List<Serializable>> en : addrUsers.entrySet()) {
|
||||||
Serializable[] us = en.getValue().toArray(new Serializable[en.getValue().size()]);
|
Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]);
|
||||||
future = future == null ? sendOneAddrAction(en.getKey(), action, us)
|
future = future == null ? sendOneAddrAction(en.getKey(), action, oneaddrUserids)
|
||||||
: future.thenCombine(sendOneAddrAction(en.getKey(), action, us), (a, b) -> a | b);
|
: future.thenCombine(sendOneAddrAction(en.getKey(), action, oneaddrUserids), (a, b) -> a | b);
|
||||||
}
|
}
|
||||||
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
||||||
});
|
});
|
||||||
@@ -720,6 +856,35 @@ public abstract class WebSocketNode {
|
|||||||
return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture;
|
return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向指定用户发送操作,先发送本地连接,再发送远程连接 <br>
|
||||||
|
* 如果当前WebSocketNode是远程模式,此方法只发送远程连接
|
||||||
|
*
|
||||||
|
* @param action 操作参数
|
||||||
|
* @param useraddrs WebSocketUserAddress[]
|
||||||
|
*
|
||||||
|
* @return 为0表示成功, 其他值表示部分发送异常
|
||||||
|
*/
|
||||||
|
@Local
|
||||||
|
public CompletableFuture<Integer> sendAction(final WebSocketAction action, final WebSocketUserAddress... useraddrs) {
|
||||||
|
if (useraddrs == null || useraddrs.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY);
|
||||||
|
if (this.localEngine != null && this.sncpNodeAddresses == null) { //本地模式且没有分布式
|
||||||
|
return this.localEngine.sendLocalAction(action, userAddressToUserids(useraddrs));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<InetSocketAddress, List<Serializable>> addrUsers = userAddressToAddrMap(useraddrs);
|
||||||
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
|
logger.finest("websocket(localaddr=" + localSncpAddress + ", useraddrs=" + JsonConvert.root().convertTo(useraddrs) + ") found action-userid-addrs: " + addrUsers);
|
||||||
|
}
|
||||||
|
CompletableFuture<Integer> future = null;
|
||||||
|
for (Map.Entry<InetSocketAddress, List<Serializable>> en : addrUsers.entrySet()) {
|
||||||
|
Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]);
|
||||||
|
future = future == null ? sendOneAddrAction(en.getKey(), action, oneaddrUserids)
|
||||||
|
: future.thenCombine(sendOneAddrAction(en.getKey(), action, oneaddrUserids), (a, b) -> a | b);
|
||||||
|
}
|
||||||
|
return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future;
|
||||||
|
}
|
||||||
|
|
||||||
protected CompletableFuture<Integer> sendOneUserAction(final WebSocketAction action, final Serializable userid) {
|
protected CompletableFuture<Integer> sendOneUserAction(final WebSocketAction action, final Serializable userid) {
|
||||||
if (logger.isLoggable(Level.FINEST)) {
|
if (logger.isLoggable(Level.FINEST)) {
|
||||||
logger.finest("websocket want send action {userid:" + userid + ", action:" + action + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
logger.finest("websocket want send action {userid:" + userid + ", action:" + action + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine");
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl
|
|||||||
webSocket._sendConvert = sendConvert;
|
webSocket._sendConvert = sendConvert;
|
||||||
webSocket._remoteAddress = request.getRemoteAddress();
|
webSocket._remoteAddress = request.getRemoteAddress();
|
||||||
webSocket._remoteAddr = request.getRemoteAddr();
|
webSocket._remoteAddr = request.getRemoteAddr();
|
||||||
|
webSocket._sncpAddress = this.node.localSncpAddress;
|
||||||
initRestWebSocket(webSocket);
|
initRestWebSocket(webSocket);
|
||||||
CompletableFuture<String> sessionFuture = webSocket.onOpen(request);
|
CompletableFuture<String> sessionFuture = webSocket.onOpen(request);
|
||||||
if (sessionFuture == null) {
|
if (sessionFuture == null) {
|
||||||
|
|||||||
107
src/org/redkale/net/http/WebSocketUserAddress.java
Normal file
107
src/org/redkale/net/http/WebSocketUserAddress.java
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.net.http;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.Collection;
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* userid 与 sncpaddress组合对象
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public interface WebSocketUserAddress extends Serializable {
|
||||||
|
|
||||||
|
Serializable userid();
|
||||||
|
|
||||||
|
InetSocketAddress sncpAddress();
|
||||||
|
|
||||||
|
Collection<InetSocketAddress> sncpAddresses();
|
||||||
|
|
||||||
|
public static WebSocketUserAddress create(WebSocketUserAddress userAddress) {
|
||||||
|
return new SimpleWebSocketUserAddress(userAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WebSocketUserAddress create(Serializable userid, InetSocketAddress sncpAddress) {
|
||||||
|
return new SimpleWebSocketUserAddress(userid, sncpAddress, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WebSocketUserAddress create(Serializable userid, Collection<InetSocketAddress> sncpAddresses) {
|
||||||
|
return new SimpleWebSocketUserAddress(userid, null, sncpAddresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SimpleWebSocketUserAddress implements WebSocketUserAddress {
|
||||||
|
|
||||||
|
private Serializable userid;
|
||||||
|
|
||||||
|
private InetSocketAddress sncpAddress;
|
||||||
|
|
||||||
|
private Collection<InetSocketAddress> sncpAddresses;
|
||||||
|
|
||||||
|
public SimpleWebSocketUserAddress() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleWebSocketUserAddress(Serializable userid, InetSocketAddress sncpAddress, Collection<InetSocketAddress> sncpAddresses) {
|
||||||
|
this.userid = userid;
|
||||||
|
this.sncpAddress = sncpAddress;
|
||||||
|
this.sncpAddresses = sncpAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleWebSocketUserAddress(WebSocketUserAddress userAddress) {
|
||||||
|
if (userAddress == null) return;
|
||||||
|
this.userid = userAddress.userid();
|
||||||
|
this.sncpAddress = userAddress.sncpAddress();
|
||||||
|
this.sncpAddresses = userAddress.sncpAddresses();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Serializable userid() {
|
||||||
|
return userid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress sncpAddress() {
|
||||||
|
return sncpAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<InetSocketAddress> sncpAddresses() {
|
||||||
|
return sncpAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Serializable getUserid() {
|
||||||
|
return userid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserid(Serializable userid) {
|
||||||
|
this.userid = userid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetSocketAddress getSncpAddress() {
|
||||||
|
return sncpAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSncpAddress(InetSocketAddress sncpAddress) {
|
||||||
|
this.sncpAddress = sncpAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<InetSocketAddress> getSncpAddresses() {
|
||||||
|
return sncpAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSncpAddresses(Collection<InetSocketAddress> sncpAddresses) {
|
||||||
|
this.sncpAddresses = sncpAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonConvert.root().convertTo(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -332,9 +332,10 @@ public final class SncpClient {
|
|||||||
return bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
|
return bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
|
||||||
} catch (RpcRemoteException re) {
|
} catch (RpcRemoteException re) {
|
||||||
throw re;
|
throw re;
|
||||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
//logger.log(Level.SEVERE, actions[index].method + " sncp (params: " + jsonConvert.convertTo(params) + ") remote error", e);
|
throw new RpcRemoteException(actions[index].method + " sncp remote timeout, params=" + JsonConvert.root().convertTo(params));
|
||||||
throw new RpcRemoteException(actions[index].method + " sncp remote error", e);
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new RpcRemoteException(actions[index].method + " sncp remote error, params=" + JsonConvert.root().convertTo(params), e);
|
||||||
} finally {
|
} finally {
|
||||||
bsonConvert.offerBsonReader(reader);
|
bsonConvert.offerBsonReader(reader);
|
||||||
}
|
}
|
||||||
@@ -348,7 +349,12 @@ public final class SncpClient {
|
|||||||
final BsonWriter writer = bsonConvert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入
|
final BsonWriter writer = bsonConvert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入
|
||||||
writer.writeTo(DEFAULT_HEADER);
|
writer.writeTo(DEFAULT_HEADER);
|
||||||
for (int i = 0; i < params.length; i++) { //params 可能包含: 3 个 boolean
|
for (int i = 0; i < params.length; i++) { //params 可能包含: 3 个 boolean
|
||||||
bsonConvert.convertTo(writer, CompletionHandler.class.isAssignableFrom(myparamclass[i]) ? CompletionHandler.class : myparamtypes[i], params[i]);
|
BsonConvert bcc = bsonConvert;
|
||||||
|
if (params[i] instanceof org.redkale.service.RetResult) {
|
||||||
|
org.redkale.convert.Convert cc = ((org.redkale.service.RetResult) params[i]).convert();
|
||||||
|
if (cc instanceof BsonConvert) bcc = (BsonConvert) cc;
|
||||||
|
}
|
||||||
|
bcc.convertTo(writer, CompletionHandler.class.isAssignableFrom(myparamclass[i]) ? CompletionHandler.class : myparamtypes[i], params[i]);
|
||||||
}
|
}
|
||||||
final int reqBodyLength = writer.count() - HEADER_SIZE; //body总长度
|
final int reqBodyLength = writer.count() - HEADER_SIZE; //body总长度
|
||||||
final long seqid = System.nanoTime();
|
final long seqid = System.nanoTime();
|
||||||
@@ -358,12 +364,12 @@ public final class SncpClient {
|
|||||||
return connFuture.thenCompose(conn0 -> {
|
return connFuture.thenCompose(conn0 -> {
|
||||||
final CompletableFuture<byte[]> future = new CompletableFuture();
|
final CompletableFuture<byte[]> future = new CompletableFuture();
|
||||||
if (conn0 == null) {
|
if (conn0 == null) {
|
||||||
future.completeExceptionally(new RuntimeException("sncp " + (conn0 == null ? addr : conn0.getRemoteAddress()) + " cannot connect"));
|
future.completeExceptionally(new RpcRemoteException("sncp " + (conn0 == null ? addr : conn0.getRemoteAddress()) + " cannot connect, params=" + JsonConvert.root().convertTo(params)));
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
if (!conn0.isOpen()) {
|
if (!conn0.isOpen()) {
|
||||||
conn0.dispose();
|
conn0.dispose();
|
||||||
future.completeExceptionally(new RuntimeException("sncp " + (conn0 == null ? addr : conn0.getRemoteAddress()) + " cannot connect"));
|
future.completeExceptionally(new RpcRemoteException("sncp " + (conn0 == null ? addr : conn0.getRemoteAddress()) + " cannot connect, params=" + JsonConvert.root().convertTo(params)));
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
final AsyncConnection conn = conn0;
|
final AsyncConnection conn = conn0;
|
||||||
@@ -403,7 +409,7 @@ public final class SncpClient {
|
|||||||
public void completed(Integer count, ByteBuffer buffer) {
|
public void completed(Integer count, ByteBuffer buffer) {
|
||||||
try {
|
try {
|
||||||
if (count < 1 && buffer.remaining() == buffer.limit()) { //没有数据可读
|
if (count < 1 && buffer.remaining() == buffer.limit()) { //没有数据可读
|
||||||
future.completeExceptionally(new RpcRemoteException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data"));
|
future.completeExceptionally(new RpcRemoteException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data, params=" + JsonConvert.root().convertTo(params)));
|
||||||
conn.offerBuffer(buffer);
|
conn.offerBuffer(buffer);
|
||||||
transport.offerConnection(true, conn);
|
transport.offerConnection(true, conn);
|
||||||
return;
|
return;
|
||||||
@@ -433,7 +439,7 @@ public final class SncpClient {
|
|||||||
final int respBodyLength = buffer.getInt();
|
final int respBodyLength = buffer.getInt();
|
||||||
final int retcode = buffer.getInt();
|
final int retcode = buffer.getInt();
|
||||||
if (retcode != 0) {
|
if (retcode != 0) {
|
||||||
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") deal error (retcode=" + retcode + ", retinfo=" + SncpResponse.getRetCodeInfo(retcode) + ")");
|
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") deal error (retcode=" + retcode + ", retinfo=" + SncpResponse.getRetCodeInfo(retcode) + "), params=" + JsonConvert.root().convertTo(params));
|
||||||
throw new RuntimeException("remote service(" + action.method + ") deal error (retcode=" + retcode + ", retinfo=" + SncpResponse.getRetCodeInfo(retcode) + ")");
|
throw new RuntimeException("remote service(" + action.method + ") deal error (retcode=" + retcode + ", retinfo=" + SncpResponse.getRetCodeInfo(retcode) + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,7 +457,7 @@ public final class SncpClient {
|
|||||||
success();
|
success();
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
future.completeExceptionally(new RuntimeException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote response error"));
|
future.completeExceptionally(new RpcRemoteException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote response error, params=" + JsonConvert.root().convertTo(params)));
|
||||||
transport.offerConnection(true, conn);
|
transport.offerConnection(true, conn);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
||||||
@@ -487,27 +493,27 @@ public final class SncpClient {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer attachment2) {
|
public void failed(Throwable exc, ByteBuffer attachment2) {
|
||||||
future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
|
future.completeExceptionally(new RpcRemoteException(action.method + " sncp remote exec failed, params=" + JsonConvert.root().convertTo(params)));
|
||||||
conn.offerBuffer(attachment2);
|
conn.offerBuffer(attachment2);
|
||||||
transport.offerConnection(true, conn);
|
transport.offerConnection(true, conn);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
||||||
handler.failed(exc, handlerAttach);
|
handler.failed(exc, handlerAttach);
|
||||||
}
|
}
|
||||||
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") remote read exec failed", exc);
|
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") remote read exec failed, params=" + JsonConvert.root().convertTo(params), exc);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failed(Throwable exc, ByteBuffer[] attachment) {
|
public void failed(Throwable exc, ByteBuffer[] attachment) {
|
||||||
future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
|
future.completeExceptionally(new RpcRemoteException(action.method + " sncp remote exec failed, params=" + JsonConvert.root().convertTo(params)));
|
||||||
transport.offerConnection(true, conn);
|
transport.offerConnection(true, conn);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
|
||||||
handler.failed(exc, handlerAttach);
|
handler.failed(exc, handlerAttach);
|
||||||
}
|
}
|
||||||
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") remote write exec failed", exc);
|
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") remote write exec failed, params=" + JsonConvert.root().convertTo(params), exc);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return future;
|
return future;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package org.redkale.service;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import org.redkale.convert.Convert;
|
||||||
import org.redkale.convert.json.*;
|
import org.redkale.convert.json.*;
|
||||||
import org.redkale.util.Utility;
|
import org.redkale.util.Utility;
|
||||||
|
|
||||||
@@ -33,6 +34,8 @@ public class RetResult<T> {
|
|||||||
|
|
||||||
protected Map<String, String> attach;
|
protected Map<String, String> attach;
|
||||||
|
|
||||||
|
protected Convert convert;
|
||||||
|
|
||||||
public RetResult() {
|
public RetResult() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +43,11 @@ public class RetResult<T> {
|
|||||||
this.result = result;
|
this.result = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RetResult(Convert convert, T result) {
|
||||||
|
this.convert = convert;
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
public RetResult(int retcode) {
|
public RetResult(int retcode) {
|
||||||
this.retcode = retcode;
|
this.retcode = retcode;
|
||||||
}
|
}
|
||||||
@@ -55,6 +63,14 @@ public class RetResult<T> {
|
|||||||
this.result = result;
|
this.result = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Convert convert() {
|
||||||
|
return convert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void convert(Convert convert) {
|
||||||
|
this.convert = convert;
|
||||||
|
}
|
||||||
|
|
||||||
public static RetResult success() {
|
public static RetResult success() {
|
||||||
return new RetResult();
|
return new RetResult();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ public class DataCallAttribute implements Attribute<Object, Serializable> {
|
|||||||
Class cltmp = clazz;
|
Class cltmp = clazz;
|
||||||
do {
|
do {
|
||||||
for (Field field : cltmp.getDeclaredFields()) {
|
for (Field field : cltmp.getDeclaredFields()) {
|
||||||
if (field.getAnnotation(javax.persistence.GeneratedValue.class) == null) continue;
|
|
||||||
try {
|
try {
|
||||||
rs = Attribute.create(cltmp, field);
|
rs = Attribute.create(cltmp, field);
|
||||||
attributes.put(clazz, rs);
|
attributes.put(clazz, rs);
|
||||||
|
|||||||
@@ -114,21 +114,7 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
c1 += cc;
|
c1 += cc;
|
||||||
}
|
}
|
||||||
c = c1;
|
c = c1;
|
||||||
}
|
}
|
||||||
if (info.autoGenerated) { //由数据库自动生成主键值
|
|
||||||
ResultSet set = prestmt.getGeneratedKeys();
|
|
||||||
int i = -1;
|
|
||||||
while (set.next()) {
|
|
||||||
if (primaryType == int.class) {
|
|
||||||
primary.set(entitys[++i], set.getInt(1));
|
|
||||||
} else if (primaryType == long.class) {
|
|
||||||
primary.set(entitys[++i], set.getLong(1));
|
|
||||||
} else {
|
|
||||||
primary.set(entitys[++i], set.getObject(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set.close();
|
|
||||||
}
|
|
||||||
prestmt.close();
|
prestmt.close();
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
if (info.isLoggable(logger, Level.FINEST)) { //打印调试信息
|
if (info.isLoggable(logger, Level.FINEST)) { //打印调试信息
|
||||||
@@ -166,10 +152,9 @@ public class DataJdbcSource extends DataSqlSource<Connection> {
|
|||||||
protected <T> PreparedStatement createInsertPreparedStatement(final Connection conn, final String sql,
|
protected <T> PreparedStatement createInsertPreparedStatement(final Connection conn, final String sql,
|
||||||
final EntityInfo<T> info, T... entitys) throws SQLException {
|
final EntityInfo<T> info, T... entitys) throws SQLException {
|
||||||
Attribute<T, Serializable>[] attrs = info.insertAttributes;
|
Attribute<T, Serializable>[] attrs = info.insertAttributes;
|
||||||
final PreparedStatement prestmt = info.autoGenerated ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
|
final PreparedStatement prestmt = conn.prepareStatement(sql);
|
||||||
|
|
||||||
for (final T value : entitys) {
|
for (final T value : entitys) {
|
||||||
if (info.autouuid) info.createPrimaryValue(value);
|
|
||||||
batchStatementParameters(conn, prestmt, info, attrs, value);
|
batchStatementParameters(conn, prestmt, info, attrs, value);
|
||||||
prestmt.addBatch();
|
prestmt.addBatch();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,11 +316,6 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
|||||||
if (entitys.length == 0) return 0;
|
if (entitys.length == 0) return 0;
|
||||||
checkEntity("insert", false, entitys);
|
checkEntity("insert", false, entitys);
|
||||||
final EntityInfo<T> info = loadEntityInfo((Class<T>) entitys[0].getClass());
|
final EntityInfo<T> info = loadEntityInfo((Class<T>) entitys[0].getClass());
|
||||||
if (info.autouuid) {
|
|
||||||
for (T value : entitys) {
|
|
||||||
info.createPrimaryValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isOnlyCache(info)) return insertCache(info, entitys);
|
if (isOnlyCache(info)) return insertCache(info, entitys);
|
||||||
return insertDB(info, entitys).whenComplete((rs, t) -> {
|
return insertDB(info, entitys).whenComplete((rs, t) -> {
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
@@ -337,11 +332,6 @@ public abstract class DataSqlSource<DBChannel> extends AbstractService implement
|
|||||||
CompletableFuture future = checkEntity("insert", true, entitys);
|
CompletableFuture future = checkEntity("insert", true, entitys);
|
||||||
if (future != null) return future;
|
if (future != null) return future;
|
||||||
final EntityInfo<T> info = loadEntityInfo((Class<T>) entitys[0].getClass());
|
final EntityInfo<T> info = loadEntityInfo((Class<T>) entitys[0].getClass());
|
||||||
if (info.autouuid) {
|
|
||||||
for (T value : entitys) {
|
|
||||||
info.createPrimaryValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isOnlyCache(info)) {
|
if (isOnlyCache(info)) {
|
||||||
return CompletableFuture.supplyAsync(() -> insertCache(info, entitys), getExecutor());
|
return CompletableFuture.supplyAsync(() -> insertCache(info, entitys), getExecutor());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,12 +154,6 @@ public final class EntityInfo<T> {
|
|||||||
//Flipper.sort转换成以ORDER BY开头SQL的缓存
|
//Flipper.sort转换成以ORDER BY开头SQL的缓存
|
||||||
private final Map<String, String> sortOrderbySqls = new ConcurrentHashMap<>();
|
private final Map<String, String> sortOrderbySqls = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
//是否由数据库生成主键值
|
|
||||||
final boolean autoGenerated;
|
|
||||||
|
|
||||||
//是否UUID主键
|
|
||||||
final boolean autouuid;
|
|
||||||
|
|
||||||
//所属的DataSource
|
//所属的DataSource
|
||||||
final DataSource source;
|
final DataSource source;
|
||||||
|
|
||||||
@@ -287,8 +281,6 @@ public final class EntityInfo<T> {
|
|||||||
List<Attribute<T, Serializable>> insertattrs = new ArrayList<>();
|
List<Attribute<T, Serializable>> insertattrs = new ArrayList<>();
|
||||||
List<String> updatecols = new ArrayList<>();
|
List<String> updatecols = new ArrayList<>();
|
||||||
List<Attribute<T, Serializable>> updateattrs = new ArrayList<>();
|
List<Attribute<T, Serializable>> updateattrs = new ArrayList<>();
|
||||||
boolean auto = false;
|
|
||||||
boolean uuid = false;
|
|
||||||
Map<Class, Creator<CryptHandler>> cryptCreatorMap = new HashMap<>();
|
Map<Class, Creator<CryptHandler>> cryptCreatorMap = new HashMap<>();
|
||||||
do {
|
do {
|
||||||
for (Field field : cltmp.getDeclaredFields()) {
|
for (Field field : cltmp.getDeclaredFields()) {
|
||||||
@@ -318,19 +310,8 @@ public final class EntityInfo<T> {
|
|||||||
}
|
}
|
||||||
if (field.getAnnotation(javax.persistence.Id.class) != null && idAttr0 == null) {
|
if (field.getAnnotation(javax.persistence.Id.class) != null && idAttr0 == null) {
|
||||||
idAttr0 = attr;
|
idAttr0 = attr;
|
||||||
GeneratedValue gv = field.getAnnotation(GeneratedValue.class);
|
insertcols.add(sqlfield);
|
||||||
auto = gv != null;
|
insertattrs.add(attr);
|
||||||
// if (gv != null && gv.strategy() != GenerationType.IDENTITY) {
|
|
||||||
// throw new RuntimeException(cltmp.getName() + "'s @ID primary not a GenerationType.IDENTITY");
|
|
||||||
// }
|
|
||||||
if (gv != null && field.getType() == String.class) { //UUID
|
|
||||||
uuid = true;
|
|
||||||
auto = false;
|
|
||||||
}
|
|
||||||
if (!auto) {
|
|
||||||
insertcols.add(sqlfield);
|
|
||||||
insertattrs.add(attr);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (col == null || col.insertable()) {
|
if (col == null || col.insertable()) {
|
||||||
insertcols.add(sqlfield);
|
insertcols.add(sqlfield);
|
||||||
@@ -456,8 +437,6 @@ public final class EntityInfo<T> {
|
|||||||
this.deleteNamesPrepareSQL = null;
|
this.deleteNamesPrepareSQL = null;
|
||||||
this.queryNamesPrepareSQL = null;
|
this.queryNamesPrepareSQL = null;
|
||||||
}
|
}
|
||||||
this.autoGenerated = auto;
|
|
||||||
this.autouuid = uuid;
|
|
||||||
//----------------cache--------------
|
//----------------cache--------------
|
||||||
Cacheable c = type.getAnnotation(Cacheable.class);
|
Cacheable c = type.getAnnotation(Cacheable.class);
|
||||||
if (this.table == null || (!cacheForbidden && c != null && c.value())) {
|
if (this.table == null || (!cacheForbidden && c != null && c.value())) {
|
||||||
@@ -482,15 +461,6 @@ public final class EntityInfo<T> {
|
|||||||
return jsonConvert;
|
return jsonConvert;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建主键值,目前只支持UUID赋值
|
|
||||||
*
|
|
||||||
* @param src Entity对象
|
|
||||||
*/
|
|
||||||
public void createPrimaryValue(T src) {
|
|
||||||
if (autouuid) getPrimary().set(src, Utility.uuid());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Entity缓存器
|
* 获取Entity缓存器
|
||||||
*
|
*
|
||||||
@@ -536,14 +506,6 @@ public final class EntityInfo<T> {
|
|||||||
return table == null;
|
return table == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAutoGenerated() {
|
|
||||||
return autoGenerated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAutouuid() {
|
|
||||||
return autouuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DistributeTableStrategy<T> getTableStrategy() {
|
public DistributeTableStrategy<T> getTableStrategy() {
|
||||||
return tableStrategy;
|
return tableStrategy;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public final class Redkale {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String getDotedVersion() {
|
public static String getDotedVersion() {
|
||||||
return "2.0.0-beta3";
|
return "2.0.0-beta5";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getMajorVersion() {
|
public static int getMajorVersion() {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.util;
|
package org.redkale.util;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -42,12 +43,22 @@ public final class ResourceFactory {
|
|||||||
|
|
||||||
private final List<WeakReference<ResourceFactory>> chidren = new CopyOnWriteArrayList<>();
|
private final List<WeakReference<ResourceFactory>> chidren = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
private final ConcurrentHashMap<Type, ResourceLoader> loadermap = new ConcurrentHashMap();
|
private final ConcurrentHashMap<Type, ResourceInjectLoader> injectLoaderMap = new ConcurrentHashMap();
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<Type, ResourceLoader> resLoaderMap = new ConcurrentHashMap();
|
||||||
|
|
||||||
private final ConcurrentHashMap<Type, ConcurrentHashMap<String, ResourceEntry>> store = new ConcurrentHashMap();
|
private final ConcurrentHashMap<Type, ConcurrentHashMap<String, ResourceEntry>> store = new ConcurrentHashMap();
|
||||||
|
|
||||||
private ResourceFactory(ResourceFactory parent) {
|
private ResourceFactory(ResourceFactory parent) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
if (parent == null) {
|
||||||
|
ServiceLoader<ResourceInjectLoader> loaders = ServiceLoader.load(ResourceInjectLoader.class);
|
||||||
|
Iterator<ResourceInjectLoader> it = loaders.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
ResourceInjectLoader ril = it.next();
|
||||||
|
this.injectLoaderMap.put(ril.annotationType(), ril);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -565,6 +576,7 @@ public final class ResourceFactory {
|
|||||||
try {
|
try {
|
||||||
list.add(src);
|
list.add(src);
|
||||||
Class clazz = src.getClass();
|
Class clazz = src.getClass();
|
||||||
|
final boolean diyloaderflag = !instance.injectLoaderMap.isEmpty();
|
||||||
do {
|
do {
|
||||||
if (java.lang.Enum.class.isAssignableFrom(clazz)) break;
|
if (java.lang.Enum.class.isAssignableFrom(clazz)) break;
|
||||||
final String cname = clazz.getName();
|
final String cname = clazz.getName();
|
||||||
@@ -586,6 +598,13 @@ public final class ResourceFactory {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (flag && diyloaderflag) {
|
||||||
|
instance.injectLoaderMap.values().stream().forEach(iloader -> {
|
||||||
|
Annotation ann = field.getAnnotation(iloader.annotationType());
|
||||||
|
if (ann == null) return;
|
||||||
|
iloader.load(this, src, ann, field, attachment);
|
||||||
|
});
|
||||||
|
}
|
||||||
if (ns == null) continue;
|
if (ns == null) continue;
|
||||||
final String nsname = ns.getClass().getName();
|
final String nsname = ns.getClass().getName();
|
||||||
if (ns.getClass().isPrimitive() || ns.getClass().isArray()
|
if (ns.getClass().isPrimitive() || ns.getClass().isArray()
|
||||||
@@ -685,16 +704,21 @@ public final class ResourceFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T extends Annotation> void register(final ResourceInjectLoader<T> loader) {
|
||||||
|
if (loader == null) return;
|
||||||
|
instance.injectLoaderMap.put(loader.annotationType(), loader);
|
||||||
|
}
|
||||||
|
|
||||||
public void register(final ResourceLoader rs, final Type... clazzs) {
|
public void register(final ResourceLoader rs, final Type... clazzs) {
|
||||||
if (clazzs == null || rs == null) return;
|
if (clazzs == null || rs == null) return;
|
||||||
for (Type clazz : clazzs) {
|
for (Type clazz : clazzs) {
|
||||||
loadermap.put(clazz, rs);
|
resLoaderMap.put(clazz, rs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceLoader findMatchLoader(Type ft, Field field) {
|
private ResourceLoader findMatchLoader(Type ft, Field field) {
|
||||||
ResourceLoader it = this.loadermap.get(ft);
|
ResourceLoader it = this.resLoaderMap.get(ft);
|
||||||
if (it == null && field != null) it = this.loadermap.get(field.getType());
|
if (it == null && field != null) it = this.resLoaderMap.get(field.getType());
|
||||||
if (it != null) return it;
|
if (it != null) return it;
|
||||||
return parent == null ? null : parent.findMatchLoader(ft, field);
|
return parent == null ? null : parent.findMatchLoader(ft, field);
|
||||||
}
|
}
|
||||||
@@ -702,7 +726,7 @@ public final class ResourceFactory {
|
|||||||
private ResourceLoader findRegxLoader(Type ft, Field field) {
|
private ResourceLoader findRegxLoader(Type ft, Field field) {
|
||||||
if (field == null) return null;
|
if (field == null) return null;
|
||||||
Class c = field.getType();
|
Class c = field.getType();
|
||||||
for (Map.Entry<Type, ResourceLoader> en : this.loadermap.entrySet()) {
|
for (Map.Entry<Type, ResourceLoader> en : this.resLoaderMap.entrySet()) {
|
||||||
Type t = en.getKey();
|
Type t = en.getKey();
|
||||||
if (t == ft) return en.getValue();
|
if (t == ft) return en.getValue();
|
||||||
if (t instanceof Class && (((Class) t)).isAssignableFrom(c)) return en.getValue();
|
if (t instanceof Class && (((Class) t)).isAssignableFrom(c)) return en.getValue();
|
||||||
|
|||||||
25
src/org/redkale/util/ResourceInjectLoader.java
Normal file
25
src/org/redkale/util/ResourceInjectLoader.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.util;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义注入加载器
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
* @param <T> Annotation
|
||||||
|
*/
|
||||||
|
public interface ResourceInjectLoader<T extends Annotation> {
|
||||||
|
|
||||||
|
public void load(ResourceFactory factory, Object src, T annotation, Field field, Object attachment);
|
||||||
|
|
||||||
|
public Class<T> annotationType();
|
||||||
|
}
|
||||||
42
src/org/redkale/util/StringWrapper.java
Normal file
42
src/org/redkale/util/StringWrapper.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.util;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主要供 JsonConvert.writeWrapper 使用
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: https://redkale.org
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class StringWrapper implements Serializable {
|
||||||
|
|
||||||
|
protected String value;
|
||||||
|
|
||||||
|
public StringWrapper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringWrapper(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -647,6 +647,180 @@ public final class Utility {
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定的long元素从数组中删除, 相同的元素会根据items里重复次数来执行删除 <br>
|
||||||
|
* 例如: <br>
|
||||||
|
* remove(new short[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]<br>
|
||||||
|
*
|
||||||
|
* @param array 原数组
|
||||||
|
* @param items short[]
|
||||||
|
*
|
||||||
|
* @return 新数组
|
||||||
|
*/
|
||||||
|
public static short[] removeMatch(final short[] array, final short... items) {
|
||||||
|
return remove(array, false, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定的int元素从数组中删除, repeat=true时相同的元素会根据items里重复次数来执行删除 <br>
|
||||||
|
* 例如: <br>
|
||||||
|
* remove(new short[]{1, 1, 1, 2, 2, 3, 3, 3}, true, 1, 1, 2, 3, 3) = [] <br>
|
||||||
|
* remove(new short[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]
|
||||||
|
*
|
||||||
|
* @param array 原数组
|
||||||
|
* @param repeat 是否重复删除相同的元素
|
||||||
|
* @param items short[]
|
||||||
|
*
|
||||||
|
* @return 新数组
|
||||||
|
*/
|
||||||
|
public static short[] remove(final short[] array, boolean repeat, final short... items) {
|
||||||
|
if (array == null || array.length == 0 || items == null || items.length == 0) return array;
|
||||||
|
final short[] news = new short[array.length];
|
||||||
|
short[] subs = items;
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < news.length; i++) {
|
||||||
|
if (subs.length > 0 && contains(subs, array[i])) {
|
||||||
|
if (!repeat) {
|
||||||
|
short[] newsubs = new short[subs.length - 1];
|
||||||
|
int k = 0;
|
||||||
|
boolean done = false;
|
||||||
|
for (short v : subs) {
|
||||||
|
if (done) {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
} else if (v == array[i]) {
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subs = newsubs;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
news[index++] = array[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index == array.length) return array;
|
||||||
|
final short[] rs = new short[index];
|
||||||
|
System.arraycopy(news, 0, rs, 0, index);
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定的long元素从数组中删除, 相同的元素会根据items里重复次数来执行删除 <br>
|
||||||
|
* 例如: <br>
|
||||||
|
* remove(new int[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]<br>
|
||||||
|
*
|
||||||
|
* @param array 原数组
|
||||||
|
* @param items int[]
|
||||||
|
*
|
||||||
|
* @return 新数组
|
||||||
|
*/
|
||||||
|
public static int[] removeMatch(final int[] array, final int... items) {
|
||||||
|
return remove(array, false, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定的int元素从数组中删除, repeat=false时相同的元素会根据items里重复次数来执行删除 <br>
|
||||||
|
* 例如: <br>
|
||||||
|
* remove(new int[]{1, 1, 1, 2, 2, 3, 3, 3}, true, 1, 1, 2, 3, 3) = [] <br>
|
||||||
|
* remove(new int[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]
|
||||||
|
*
|
||||||
|
* @param array 原数组
|
||||||
|
* @param repeat 是否重复删除相同的元素
|
||||||
|
* @param items int[]
|
||||||
|
*
|
||||||
|
* @return 新数组
|
||||||
|
*/
|
||||||
|
public static int[] remove(final int[] array, boolean repeat, final int... items) {
|
||||||
|
if (array == null || array.length == 0 || items == null || items.length == 0) return array;
|
||||||
|
final int[] news = new int[array.length];
|
||||||
|
int[] subs = items;
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < news.length; i++) {
|
||||||
|
if (subs.length > 0 && contains(subs, array[i])) {
|
||||||
|
if (!repeat) {
|
||||||
|
int[] newsubs = new int[subs.length - 1];
|
||||||
|
int k = 0;
|
||||||
|
boolean done = false;
|
||||||
|
for (int v : subs) {
|
||||||
|
if (done) {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
} else if (v == array[i]) {
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subs = newsubs;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
news[index++] = array[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index == array.length) return array;
|
||||||
|
final int[] rs = new int[index];
|
||||||
|
System.arraycopy(news, 0, rs, 0, index);
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定的long元素从数组中删除, 相同的元素会根据items里重复次数来执行删除 <br>
|
||||||
|
* 例如: <br>
|
||||||
|
* remove(new long[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]<br>
|
||||||
|
*
|
||||||
|
* @param array 原数组
|
||||||
|
* @param items long[]
|
||||||
|
*
|
||||||
|
* @return 新数组
|
||||||
|
*/
|
||||||
|
public static long[] removeMatch(final long[] array, final long... items) {
|
||||||
|
return remove(array, false, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定的long元素从数组中删除, repeat=false时相同的元素会根据items里重复次数来执行删除 <br>
|
||||||
|
* 例如: <br>
|
||||||
|
* remove(new long[]{1, 1, 1, 2, 2, 3, 3, 3}, true, 1, 1, 2, 3, 3) = [] <br>
|
||||||
|
* remove(new long[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]<br>
|
||||||
|
*
|
||||||
|
* @param array 原数组
|
||||||
|
* @param repeat 是否重复删除相同的元素
|
||||||
|
* @param items long[]
|
||||||
|
*
|
||||||
|
* @return 新数组
|
||||||
|
*/
|
||||||
|
public static long[] remove(final long[] array, boolean repeat, final long... items) {
|
||||||
|
if (array == null || array.length == 0 || items == null || items.length == 0) return array;
|
||||||
|
final long[] news = new long[array.length];
|
||||||
|
long[] subs = items;
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < news.length; i++) {
|
||||||
|
if (subs.length > 0 && contains(subs, array[i])) {
|
||||||
|
if (!repeat) {
|
||||||
|
long[] newsubs = new long[subs.length - 1];
|
||||||
|
int k = 0;
|
||||||
|
boolean done = false;
|
||||||
|
for (long v : subs) {
|
||||||
|
if (done) {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
} else if (v == array[i]) {
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subs = newsubs;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
news[index++] = array[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index == array.length) return array;
|
||||||
|
final long[] rs = new long[index];
|
||||||
|
System.arraycopy(news, 0, rs, 0, index);
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断字符串是否包含指定的字符,包含返回true
|
* 判断字符串是否包含指定的字符,包含返回true
|
||||||
*
|
*
|
||||||
@@ -697,6 +871,22 @@ public final class Utility {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断指定值(不要包含相同的元素)是否包含指定的数组中,包含返回true
|
||||||
|
*
|
||||||
|
* @param values 集合
|
||||||
|
* @param items 多值
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static boolean contains(short[] values, short... items) {
|
||||||
|
if (values == null) return false;
|
||||||
|
for (short item : items) {
|
||||||
|
if (!contains(values, item)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断指定值是否包含指定的数组中,包含返回true
|
* 判断指定值是否包含指定的数组中,包含返回true
|
||||||
*
|
*
|
||||||
@@ -713,6 +903,22 @@ public final class Utility {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断指定值(不要包含相同的元素)是否包含指定的数组中,包含返回true
|
||||||
|
*
|
||||||
|
* @param values 集合
|
||||||
|
* @param items 多值
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static boolean contains(int[] values, int... items) {
|
||||||
|
if (values == null) return false;
|
||||||
|
for (int item : items) {
|
||||||
|
if (!contains(values, item)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断指定值是否包含指定的数组中,包含返回true
|
* 判断指定值是否包含指定的数组中,包含返回true
|
||||||
*
|
*
|
||||||
@@ -729,6 +935,22 @@ public final class Utility {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断指定值(不要包含相同的元素)是否包含指定的数组中,包含返回true
|
||||||
|
*
|
||||||
|
* @param values 集合
|
||||||
|
* @param items 多值
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static boolean contains(long[] values, long... items) {
|
||||||
|
if (values == null) return false;
|
||||||
|
for (long item : items) {
|
||||||
|
if (!contains(values, item)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断指定值是否包含指定的数组中,包含返回true
|
* 判断指定值是否包含指定的数组中,包含返回true
|
||||||
*
|
*
|
||||||
@@ -746,6 +968,117 @@ public final class Utility {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定的short元素是否数组中完全包含,重复元素的次数也要相同 <br>
|
||||||
|
* 例如: <br>
|
||||||
|
* containsMatch(new short[]{1, 2, 2, 3, 3, 3}, 1, 2, 3, 3) = true <br>
|
||||||
|
* containsMatch(new short[]{1, 2, 2, 3, 3, 3}, 1, 1, 2, 3, 3) = false <br>
|
||||||
|
*
|
||||||
|
* @param array 原数组
|
||||||
|
* @param items short[]
|
||||||
|
*
|
||||||
|
* @return 是否完全包含
|
||||||
|
*/
|
||||||
|
public static boolean containsMatch(final short[] array, final short... items) {
|
||||||
|
if (array == null) return false;
|
||||||
|
if (items == null || items.length == 0) return true;
|
||||||
|
if (array.length == 0 && items.length == 0) return true;
|
||||||
|
if (array.length < items.length) return false;
|
||||||
|
|
||||||
|
short[] subs = array;
|
||||||
|
for (short item : items) {
|
||||||
|
if (!contains(subs, item)) return false;
|
||||||
|
short[] newsubs = new short[subs.length - 1];
|
||||||
|
int k = 0;
|
||||||
|
boolean done = false;
|
||||||
|
for (short v : subs) {
|
||||||
|
if (done) {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
} else if (v == item) {
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subs = newsubs;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定的int元素是否数组中完全包含,重复元素的次数也要相同 <br>
|
||||||
|
* 例如: <br>
|
||||||
|
* containsMatch(new int[]{1, 2, 2, 3, 3, 3}, 1, 2, 3, 3) = true <br>
|
||||||
|
* containsMatch(new int[]{1, 2, 2, 3, 3, 3}, 1, 1, 2, 3, 3) = false <br>
|
||||||
|
*
|
||||||
|
* @param array 原数组
|
||||||
|
* @param items int[]
|
||||||
|
*
|
||||||
|
* @return 是否完全包含
|
||||||
|
*/
|
||||||
|
public static boolean containsMatch(final int[] array, final int... items) {
|
||||||
|
if (array == null) return false;
|
||||||
|
if (items == null || items.length == 0) return true;
|
||||||
|
if (array.length == 0 && items.length == 0) return true;
|
||||||
|
if (array.length < items.length) return false;
|
||||||
|
|
||||||
|
int[] subs = array;
|
||||||
|
for (int item : items) {
|
||||||
|
if (!contains(subs, item)) return false;
|
||||||
|
int[] newsubs = new int[subs.length - 1];
|
||||||
|
int k = 0;
|
||||||
|
boolean done = false;
|
||||||
|
for (int v : subs) {
|
||||||
|
if (done) {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
} else if (v == item) {
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subs = newsubs;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定的long元素是否数组中完全包含,重复元素的次数也要相同 <br>
|
||||||
|
* 例如: <br>
|
||||||
|
* containsMatch(new long[]{1, 2, 2, 3, 3, 3}, 1, 2, 3, 3) = true <br>
|
||||||
|
* containsMatch(new long[]{1, 2, 2, 3, 3, 3}, 1, 1, 2, 3, 3) = false <br>
|
||||||
|
*
|
||||||
|
* @param array 原数组
|
||||||
|
* @param items long[]
|
||||||
|
*
|
||||||
|
* @return 是否完全包含
|
||||||
|
*/
|
||||||
|
public static boolean containsMatch(final long[] array, final long... items) {
|
||||||
|
if (array == null) return false;
|
||||||
|
if (items == null || items.length == 0) return true;
|
||||||
|
if (array.length == 0 && items.length == 0) return true;
|
||||||
|
if (array.length < items.length) return false;
|
||||||
|
|
||||||
|
long[] subs = array;
|
||||||
|
for (long item : items) {
|
||||||
|
if (!contains(subs, item)) return false;
|
||||||
|
long[] newsubs = new long[subs.length - 1];
|
||||||
|
int k = 0;
|
||||||
|
boolean done = false;
|
||||||
|
for (long v : subs) {
|
||||||
|
if (done) {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
} else if (v == item) {
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
newsubs[k++] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subs = newsubs;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除掉字符串数组中包含指定的字符串
|
* 删除掉字符串数组中包含指定的字符串
|
||||||
*
|
*
|
||||||
@@ -1591,7 +1924,15 @@ public final class Utility {
|
|||||||
final int limit = start + len;
|
final int limit = start + len;
|
||||||
for (int i = start; i < limit; i++) {
|
for (int i = start; i < limit; i++) {
|
||||||
c = chars[i];
|
c = chars[i];
|
||||||
size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3));
|
if (c < 0x80) {
|
||||||
|
size++;
|
||||||
|
} else if (c < 0x800) {
|
||||||
|
size += 2;
|
||||||
|
} else if (Character.isSurrogate(c)) {
|
||||||
|
size += 2;
|
||||||
|
} else {
|
||||||
|
size += 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
@@ -1612,12 +1953,13 @@ public final class Utility {
|
|||||||
return encodeUTF8(buffer, encodeUTF8Length(text, start, len), text, start, len);
|
return encodeUTF8(buffer, encodeUTF8Length(text, start, len), text, start, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//返回的ByteBuffer为扩展buffer,为null表示参数中的buffer足够存储数据
|
||||||
public static ByteBuffer encodeUTF8(final ByteBuffer buffer, int bytesLength, final char[] text, final int start, final int len) {
|
public static ByteBuffer encodeUTF8(final ByteBuffer buffer, int bytesLength, final char[] text, final int start, final int len) {
|
||||||
char c;
|
char c;
|
||||||
char[] chars = text;
|
char[] chars = text;
|
||||||
final int limit = start + len;
|
final int limit = start + len;
|
||||||
int remain = buffer.remaining();
|
int remain = buffer.remaining();
|
||||||
final ByteBuffer buffer2 = remain >= bytesLength ? null : ByteBuffer.allocate(bytesLength - remain + 3); //最差情况buffer最后两byte没有填充
|
final ByteBuffer buffer2 = remain >= bytesLength ? null : ByteBuffer.allocate(bytesLength - remain + 4); //最差情况buffer最后两byte没有填充
|
||||||
ByteBuffer buf = buffer;
|
ByteBuffer buf = buffer;
|
||||||
for (int i = start; i < limit; i++) {
|
for (int i = start; i < limit; i++) {
|
||||||
c = chars[i];
|
c = chars[i];
|
||||||
@@ -1628,6 +1970,14 @@ public final class Utility {
|
|||||||
if (buf.remaining() < 2) buf = buffer2;
|
if (buf.remaining() < 2) buf = buffer2;
|
||||||
buf.put((byte) (0xc0 | (c >> 6)));
|
buf.put((byte) (0xc0 | (c >> 6)));
|
||||||
buf.put((byte) (0x80 | (c & 0x3f)));
|
buf.put((byte) (0x80 | (c & 0x3f)));
|
||||||
|
} else if (Character.isSurrogate(c)) { //连取两个
|
||||||
|
if (buf.remaining() < 4) buf = buffer2;
|
||||||
|
int uc = Character.toCodePoint(c, chars[i + 1]);
|
||||||
|
buf.put((byte) (0xf0 | ((uc >> 18))));
|
||||||
|
buf.put((byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||||
|
buf.put((byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||||
|
buf.put((byte) (0x80 | (uc & 0x3f)));
|
||||||
|
i++;
|
||||||
} else {
|
} else {
|
||||||
if (buf.remaining() < 3) buf = buffer2;
|
if (buf.remaining() < 3) buf = buffer2;
|
||||||
buf.put((byte) (0xe0 | ((c >> 12))));
|
buf.put((byte) (0xe0 | ((c >> 12))));
|
||||||
@@ -1636,7 +1986,7 @@ public final class Utility {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (buffer2 != null) buffer2.flip();
|
if (buffer2 != null) buffer2.flip();
|
||||||
return buffer2;
|
return buffer2; //返回扩展buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getTypeDescriptor(java.lang.reflect.Type type) {
|
public static String getTypeDescriptor(java.lang.reflect.Type type) {
|
||||||
|
|||||||
58
test/org/redkale/test/convert/BiFunctionConvertMain.java
Normal file
58
test/org/redkale/test/convert/BiFunctionConvertMain.java
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.test.convert;
|
||||||
|
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
import org.redkale.util.Attribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class BiFunctionConvertMain {
|
||||||
|
|
||||||
|
public static class GamePlayer {
|
||||||
|
public int userid;
|
||||||
|
public String username;
|
||||||
|
public int[] cards;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GameTable {
|
||||||
|
public int tableid;
|
||||||
|
public GamePlayer[] players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Throwable {
|
||||||
|
GamePlayer player1 = new GamePlayer();
|
||||||
|
player1.userid= 1;
|
||||||
|
player1.username="玩家1";
|
||||||
|
player1.cards = new int[]{11,12,13,14,15};
|
||||||
|
GamePlayer player2 = new GamePlayer();
|
||||||
|
player2.userid= 2;
|
||||||
|
player2.username="玩家2";
|
||||||
|
player2.cards = new int[]{21,22,23,24,25};
|
||||||
|
GamePlayer player3 = new GamePlayer();
|
||||||
|
player3.userid= 3;
|
||||||
|
player3.username="玩家3";
|
||||||
|
player3.cards = new int[]{31,32,33,34,35};
|
||||||
|
GameTable table = new GameTable();
|
||||||
|
table.tableid=100;
|
||||||
|
table.players = new GamePlayer[]{player1,player2,player3};
|
||||||
|
JsonConvert convert1 = JsonConvert.root();
|
||||||
|
System.out.println(convert1.convertTo(table));
|
||||||
|
JsonConvert convert2 = convert1.newConvert((Attribute t, Object u) -> {
|
||||||
|
if(t.field().equals("cards") && u instanceof GamePlayer){
|
||||||
|
int userid = ((GamePlayer)u).userid;
|
||||||
|
if(userid == 3) return null; //玩家3的cards不输出
|
||||||
|
return t.get(u);
|
||||||
|
}
|
||||||
|
return t.get(u);
|
||||||
|
});
|
||||||
|
System.out.println(convert2.convertTo(table));
|
||||||
|
//{"players":[{"cards":[11,12,13,14,15],"userid":1,"username":"玩家1"},{"cards":[21,22,23,24,25],"userid":2,"username":"玩家2"},{"cards":[31,32,33,34,35],"userid":3,"username":"玩家3"}],"tableid":100}
|
||||||
|
//{"players":[{"cards":[11,12,13,14,15],"userid":1,"username":"玩家1"},{"cards":[21,22,23,24,25],"userid":2,"username":"玩家2"},{"userid":3,"username":"玩家3"}],"tableid":100}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,6 @@ import org.redkale.convert.json.*;
|
|||||||
public class SncpTestBean implements FilterBean {
|
public class SncpTestBean implements FilterBean {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue
|
|
||||||
private long id;
|
private long id;
|
||||||
|
|
||||||
private String content;
|
private String content;
|
||||||
|
|||||||
@@ -21,12 +21,9 @@ import org.redkale.convert.json.*;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
@Entity
|
|
||||||
public class LoginTestRecord {
|
public class LoginTestRecord {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue
|
|
||||||
//@SequenceGenerator(name = "SEQ", initialValue = 100001, allocationSize = 1000)
|
|
||||||
private String sessionid;
|
private String sessionid;
|
||||||
|
|
||||||
private int userid;
|
private int userid;
|
||||||
|
|||||||
67
test/org/redkale/test/util/ResourceInjectMain.java
Normal file
67
test/org/redkale/test/util/ResourceInjectMain.java
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.redkale.test.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
import static java.lang.annotation.ElementType.FIELD;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import org.redkale.convert.json.JsonConvert;
|
||||||
|
import org.redkale.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class ResourceInjectMain {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Throwable {
|
||||||
|
ResourceFactory factory = ResourceFactory.root();
|
||||||
|
factory.register(new CustomConfLoader());
|
||||||
|
InjectBean bean = new InjectBean();
|
||||||
|
factory.inject(bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CustomConfLoader implements ResourceInjectLoader<CustomConf> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(ResourceFactory factory, Object src, CustomConf annotation, Field field, Object attachment) {
|
||||||
|
try {
|
||||||
|
field.set(src, new File(annotation.path()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
System.out.println("对象是 src =" + src + ", path=" + annotation.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<CustomConf> annotationType() {
|
||||||
|
return CustomConf.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InjectBean {
|
||||||
|
|
||||||
|
@CustomConf(path = "conf/test.xml")
|
||||||
|
public File conf;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonConvert.root().convertTo(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Target({FIELD})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public static @interface CustomConf {
|
||||||
|
|
||||||
|
String path();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user