This commit is contained in:
Redkale
2017-05-27 17:54:55 +08:00
parent a8b9cc9753
commit 37f8208b1b
14 changed files with 212 additions and 321 deletions

View File

@@ -415,7 +415,7 @@ public final class Application {
return false;
}
}, Application.class, WatchFactory.class, NodeSncpServer.class, NodeHttpServer.class, NodeWatchServer.class);
}, Application.class, NodeSncpServer.class, NodeHttpServer.class, NodeWatchServer.class);
//--------------------------------------------------------------------------
initResources();
}

View File

@@ -55,6 +55,14 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
}
}
protected void removeServlet(S servlet) {
synchronized (lock1) {
Set<S> newservlets = new HashSet<>(servlets);
newservlets.remove(servlet);
this.servlets = newservlets;
}
}
protected void putMapping(K key, S servlet) {
synchronized (lock2) {
Map<K, S> newmappings = new HashMap<>(mappings);
@@ -63,6 +71,28 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
}
}
protected void removeMapping(K key) {
synchronized (lock2) {
Map<K, S> newmappings = new HashMap<>(mappings);
newmappings.remove(key);
this.mappings = newmappings;
}
}
protected void removeMapping(S servlet) {
synchronized (lock2) {
List<K> keys = new ArrayList<>();
Map<K, S> newmappings = new HashMap<>(mappings);
for (Map.Entry<K, S> en : newmappings.entrySet()) {
if (en.getValue().equals(servlet)) {
keys.add(en.getKey());
}
}
for (K key : keys) newmappings.remove(key);
this.mappings = newmappings;
}
}
protected S mappingServlet(K key) {
return mappings.get(key);
}

View File

@@ -8,7 +8,6 @@ package org.redkale.net.http;
import org.redkale.util.AnyValue.DefaultAnyValue;
import java.io.*;
import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.function.*;
import java.util.logging.*;
import java.util.regex.*;
@@ -28,12 +27,12 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
protected SimpleEntry<Predicate<String>, HttpServlet>[] regArray = null; //regArray 包含 regWsArray
protected MappingEntry[] regArray = null; //regArray 包含 regWsArray
protected MappingEntry[] regWsArray = null;
protected Map<String, WebSocketServlet> wsmappings = new HashMap<>(); //super.mappings 包含 wsmappings
protected SimpleEntry<Predicate<String>, WebSocketServlet>[] regWsArray = null;
protected HttpServlet resourceHttpServlet = new HttpResourceServlet();
protected final Map<String, Class> allMapStrings = new HashMap<>();
@@ -44,6 +43,30 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
private BiPredicate<String, String>[] forbidURIPredicates; //禁用的URL的Predicate, 必须与 forbidURIMaps 保持一致
public HttpServlet removeHttpServlet(HttpServlet servlet) {
HttpServlet rs = null;
synchronized (allMapStrings) {
//待开发
}
return rs;
}
public <T extends HttpServlet> HttpServlet removeHttpServlet(Class<T> servletType) {
HttpServlet rs = null;
synchronized (allMapStrings) {
//待开发
}
return rs;
}
public HttpServlet removeHttpServlet(String mapping) {
HttpServlet rs = null;
synchronized (allMapStrings) {
//待开发
}
return rs;
}
public boolean addForbidURIReg(final String urlreg) {
if (urlreg == null || urlreg.isEmpty()) return false;
synchronized (excludeLock) {
@@ -140,9 +163,9 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
if (request.isWebSocket()) {
servlet = wsmappings.get(uri);
if (servlet == null && this.regWsArray != null) {
for (SimpleEntry<Predicate<String>, WebSocketServlet> en : regWsArray) {
if (en.getKey().test(uri)) {
servlet = en.getValue();
for (MappingEntry en : regWsArray) {
if (en.predicate.test(uri)) {
servlet = en.servlet;
break;
}
}
@@ -154,9 +177,9 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
} else {
servlet = mappingServlet(uri);
if (servlet == null && this.regArray != null) {
for (SimpleEntry<Predicate<String>, HttpServlet> en : regArray) {
if (en.getKey().test(uri)) {
servlet = en.getValue();
for (MappingEntry en : regArray) {
if (en.predicate.test(uri)) {
servlet = en.servlet;
break;
}
}
@@ -216,19 +239,19 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
mapping = mapping + "$";
}
if (regArray == null) {
regArray = new SimpleEntry[1];
regArray[0] = new SimpleEntry<>(Pattern.compile(mapping).asPredicate(), servlet);
regArray = new MappingEntry[1];
regArray[0] = new MappingEntry(mapping, Pattern.compile(mapping).asPredicate(), servlet);
} else {
regArray = Arrays.copyOf(regArray, regArray.length + 1);
regArray[regArray.length - 1] = new SimpleEntry<>(Pattern.compile(mapping).asPredicate(), servlet);
regArray[regArray.length - 1] = new MappingEntry(mapping, Pattern.compile(mapping).asPredicate(), servlet);
}
if (servlet instanceof WebSocketServlet) {
if (regWsArray == null) {
regWsArray = new SimpleEntry[1];
regWsArray[0] = new SimpleEntry<>(Pattern.compile(mapping).asPredicate(), (WebSocketServlet) servlet);
regWsArray = new MappingEntry[1];
regWsArray[0] = new MappingEntry(mapping, Pattern.compile(mapping).asPredicate(), (WebSocketServlet) servlet);
} else {
regWsArray = Arrays.copyOf(regWsArray, regWsArray.length + 1);
regWsArray[regWsArray.length - 1] = new SimpleEntry<>(Pattern.compile(mapping).asPredicate(), (WebSocketServlet) servlet);
regWsArray[regWsArray.length - 1] = new MappingEntry(mapping, Pattern.compile(mapping).asPredicate(), (WebSocketServlet) servlet);
}
}
} else if (mapping != null && !mapping.isEmpty()) {
@@ -285,4 +308,19 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
this.regWsArray = null;
}
protected static class MappingEntry {
public final String mapping;
public final Predicate<String> predicate;
public final HttpServlet servlet;
public MappingEntry(String mapping, Predicate<String> predicate, HttpServlet servlet) {
this.mapping = mapping;
this.predicate = predicate;
this.servlet = servlet;
}
}
}

View File

@@ -57,6 +57,40 @@ public class HttpServer extends Server<String, HttpContext, HttpRequest, HttpRes
return (HttpFilter) this.prepare.removeFilter(filterName);
}
/**
* 删除HttpServlet
*
* @param servlet HttpServlet
*
* @return HttpServlet
*/
public HttpServlet removeHttpServlet(HttpServlet servlet) {
return ((HttpPrepareServlet) this.prepare).removeHttpServlet(servlet);
}
/**
* 删除HttpServlet
*
* @param <T> 泛型
* @param servletType Class
*
* @return HttpServlet
*/
public <T extends HttpServlet> HttpServlet removeHttpServlet(Class<T> servletType) {
return ((HttpPrepareServlet) this.prepare).removeHttpServlet(servletType);
}
/**
* 删除HttpServlet
*
* @param mapping String
*
* @return HttpServlet
*/
public HttpServlet removeHttpServlet(String mapping) {
return ((HttpPrepareServlet) this.prepare).removeHttpServlet(mapping);
}
/**
* 屏蔽请求URL的正则表达式
*

View File

@@ -42,10 +42,6 @@ public final class SncpDynServlet extends SncpServlet {
private final boolean finest = logger.isLoggable(Level.FINEST);
private final Class<? extends Service> type;
private final String serviceName;
private final DLong serviceid;
private final HashMap<DLong, SncpServletAction> actions = new HashMap<>();
@@ -53,8 +49,7 @@ public final class SncpDynServlet extends SncpServlet {
private Supplier<ByteBuffer> bufferSupplier;
public SncpDynServlet(final BsonConvert convert, final String serviceName, final Class<? extends Service> type, final Service service) {
this.serviceName = serviceName;
this.type = type;
super(serviceName, type, service);
this.serviceid = Sncp.hash(type.getName() + ':' + serviceName);
Set<DLong> actionids = new HashSet<>();
for (java.lang.reflect.Method method : service.getClass().getMethods()) {

View File

@@ -25,15 +25,30 @@ public class SncpPrepareServlet extends PrepareServlet<DLong, SncpContext, SncpR
@Override
public void addServlet(SncpServlet servlet, Object attachment, AnyValue conf, DLong... mappings) {
addServlet((SncpServlet) servlet, conf);
addSncpServlet((SncpServlet) servlet, conf);
}
public void addServlet(SncpServlet servlet, AnyValue conf) {
public void addSncpServlet(SncpServlet servlet, AnyValue conf) {
setServletConf(servlet, conf);
putMapping(servlet.getServiceid(), servlet);
putServlet(servlet);
}
public <T> SncpServlet removeSncpServlet(String name, Class<T> type) {
SncpServlet rs = null;
for (SncpServlet servlet : getServlets()) {
if (servlet.serviceName.equals(name) && servlet.type.equals(type)) {
rs = servlet;
break;
}
}
if (rs != null) {
removeMapping(rs);
removeServlet(rs);
}
return rs;
}
public List<SncpServlet> getSncpServlets() {
return new ArrayList<>(getServlets());
}

View File

@@ -73,6 +73,35 @@ public class SncpServer extends Server<DLong, SncpContext, SncpRequest, SncpResp
return this;
}
/**
* 删除SncpServlet
*
* @param <T> 泛型
* @param resname String
* @param type Class
*
* @return SncpServlet
*/
public <T extends Service> SncpServlet removeSncpServlet(String resname, Class<T> type) {
return ((SncpPrepareServlet) this.prepare).removeSncpServlet(resname, type);
}
/**
* 删除SncpServlet
*
* @param sncpService Service
*
* @return SncpServlet
*/
public SncpServlet removeSncpServlet(Service sncpService) {
SncpServlet servlet = null;
String resname = Sncp.getResourceName(sncpService);
for (Class type : Sncp.getResourceTypes(sncpService)) {
servlet = ((SncpPrepareServlet) this.prepare).removeSncpServlet(resname, type);
}
return servlet;
}
public void addSncpServlet(Service sncpService) {
for (Class type : Sncp.getResourceTypes(sncpService)) {
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), Sncp.getResourceName(sncpService), type, sncpService);

View File

@@ -8,6 +8,7 @@ package org.redkale.net.sncp;
import java.util.Objects;
import java.util.concurrent.*;
import org.redkale.net.*;
import org.redkale.service.Service;
import org.redkale.util.*;
/**
@@ -19,6 +20,26 @@ import org.redkale.util.*;
*/
public abstract class SncpServlet extends Servlet<SncpContext, SncpRequest, SncpResponse> implements Comparable<SncpServlet> {
protected final Class<? extends Service> type;
protected final String serviceName;
protected final Service service;
protected SncpServlet(String serviceName, Class<? extends Service> type, Service service) {
this.type = type;
this.service = service;
this.serviceName = serviceName;
}
public Service getService() {
return service;
}
public String getServiceName() {
return serviceName;
}
public abstract DLong getServiceid();
protected ExecutorService getExecutor() {

View File

@@ -11,6 +11,7 @@ import java.nio.ByteBuffer;
import java.nio.charset.*;
import java.time.*;
import java.util.*;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;
import javax.net.ssl.*;
@@ -276,6 +277,30 @@ public final class Utility {
return news;
}
/**
* 将符合条件的元素从数组中删除
*
* @param <T> 泛型
* @param array 原数组
* @param filter Predicate
*
* @return 新数组
*/
public static <T> T[] remove(final T[] array, final Predicate filter) {
if (array == null || array.length == 0 || filter == null) return array;
final T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length);
int index = 0;
for (int i = 0; i < news.length; i++) {
if (!filter.test(array[i])) {
news[index++] = array[i];
}
}
if (index == news.length) return news;
final T[] rs = (T[]) Array.newInstance(array.getClass().getComponentType(), index);
System.arraycopy(news, 0, rs, 0, index);
return rs;
}
/**
* 判断字符串是否包含指定的字符包含返回true
*

View File

@@ -1,137 +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.watch;
import java.lang.ref.WeakReference;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.LongSupplier;
/**
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public final class WatchFactory {
private static final WatchFactory instance = new WatchFactory("", null);
private final List<WeakReference<WatchFactory>> chidren = new CopyOnWriteArrayList<>();
private final List<WeakReference<WatchNode>> beans = new CopyOnWriteArrayList<>();
private final String name;
private final WatchFactory parent;
private WatchFactory(String name, WatchFactory parent) {
this.name = name;
this.parent = parent;
}
public void register(WatchNode bean) {
if (bean == null) return;
checkName(bean.getName());
beans.add(new WeakReference<>(bean));
}
public static WatchFactory root() {
return instance;
}
public WatchFactory createChild(final String name) {
WatchFactory child = new WatchFactory(name, this);
this.chidren.add(new WeakReference<>(child));
return child;
}
public List<WatchFactory> getChildren() {
List<WatchFactory> result = new ArrayList<>();
for (WeakReference<WatchFactory> ref : chidren) {
WatchFactory rf = ref.get();
if (rf != null) result.add(rf);
}
return result;
}
public List<WatchNode> getWatchNodes() {
List<WatchNode> result = new ArrayList<>();
for (WeakReference<WatchNode> ref : beans) {
WatchNode rf = ref.get();
if (rf != null) result.add(rf);
}
return result;
}
public WatchNumber createWatchNumber(String name) {
return createWatchNumber(name, "", false, 0);
}
public WatchNumber createWatchNumber(String name, boolean interval) {
return createWatchNumber(name, "", interval, 0);
}
public WatchNumber createWatchNumber(String name, String description) {
return createWatchNumber(name, description, false, 0);
}
public WatchNumber createWatchNumber(String name, String description, long v) {
return createWatchNumber(name, description, false, 0);
}
public WatchNumber createWatchNumber(String name, String description, boolean interval) {
return createWatchNumber(name, description, interval, 0);
}
public WatchNumber createWatchNumber(String name, String description, boolean interval, long v) {
return new WatchNumber(name, description, interval, v);
}
public void register(String name, LongSupplier supplier) {
register(name, "", supplier);
}
public void register(String name, String description, LongSupplier supplier) {
register(new WatchSupplier(name, description, supplier));
}
public void checkName(String name) {
if (name == null || (!name.isEmpty() && !name.matches("^[a-zA-Z0-9_;/\\-\\.\\[\\]\\(\\)]+$")) || name.contains("//")) {
throw new IllegalArgumentException("Watch.name(" + name + ") contains illegal character, must be (a-z,A-Z,0-9,/,_,.,(,),-,[,]) and cannot contains //");
}
}
protected <T> boolean inject(final Object src) {
return inject(src, null);
}
protected <T> boolean inject(final Object src, final T attachment) {
return inject(src, attachment, new ArrayList<>());
}
private <T> boolean inject(final Object src, final T attachment, final List<Object> list) {
if (src == null) return false;
try {
list.add(src);
Class clazz = src.getClass();
do {
for (Field field : clazz.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue;
field.setAccessible(true);
final Class type = field.getType();
Watchable wo = field.getAnnotation(Watchable.class);
if (wo == null && !WatchNode.class.isAssignableFrom(type)) continue;
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
return true;
} catch (Exception ex) {
return false;
}
}
}

View File

@@ -1,22 +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.watch;
/**
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
interface WatchNode {
public String getName();
public String getDescription();
public long getValue();
public boolean isInterval();
}

View File

@@ -1,52 +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.watch;
import java.beans.*;
import java.util.concurrent.atomic.*;
/**
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
final class WatchNumber extends AtomicLong implements WatchNode {
private final boolean interval;
private final String name;
private final String description;
@ConstructorProperties({"name", "description", "interval", "value"})
protected WatchNumber(String name, String description, boolean interval, long value) {
this.name = name;
this.description = description;
this.interval = interval;
this.set(value);
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public long getValue() {
return super.longValue();
}
@Override
public boolean isInterval() {
return interval;
}
}

View File

@@ -1,48 +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.watch;
import java.util.function.LongSupplier;
/**
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
public final class WatchSupplier implements WatchNode {
private final String name;
private final String description;
private final LongSupplier supplier;
WatchSupplier(String name, String description, LongSupplier supplier) {
this.name = name;
this.description = description;
this.supplier = supplier;
}
@Override
public String getName() {
return this.name;
}
@Override
public String getDescription() {
return this.description;
}
@Override
public long getValue() {
return supplier == null ? Long.MIN_VALUE : supplier.getAsLong();
}
@Override
public boolean isInterval() {
return false;
}
}

View File

@@ -1,37 +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.watch;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 该注解只能放在field类型为Collection, Map, 或者java.util.concurrent.atomic.AtomicXXX的Number类);
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({FIELD, METHOD})
@Retention(RUNTIME)
@interface Watchable {
String name();
String description() default "";
/**
* 该值指明是不是只收集阶段数据, 而且被注解的字段只能被赋予java.util.concurrent.atomic.AtomicXXX的Number类型字段。
* 例如收集每分钟的注册用户数, 就需要将interval设置true。
*
* @return 是否收集
*/
boolean interval() default false;
}