This commit is contained in:
Redkale
2017-05-14 11:34:15 +08:00
parent 6d74355fc0
commit 853e823a8d
14 changed files with 290 additions and 61 deletions

View File

@@ -11,7 +11,6 @@ import java.util.*;
import javax.persistence.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.*;
import org.redkale.service.*;
import org.redkale.source.*;
import org.redkale.util.*;
@@ -24,9 +23,7 @@ import org.redkale.util.*;
*
* @author zhangjx
*/
@AutoLoad(false)
@Local
public final class ApiDocsService extends AbstractService {
public final class ApiDocsService {
private final Application app; //Application全局对象

View File

@@ -26,7 +26,7 @@ import org.redkale.service.Service;
import org.redkale.source.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*;
import org.redkale.watch.WatchFactory;
import org.redkale.watch.*;
import org.w3c.dom.*;
/**
@@ -142,15 +142,15 @@ public final class Application {
//Server启动的计数器用于确保所有Server都启动完后再进行下一步处理
private final CountDownLatch serversLatch;
private Application(final AnyValue config) {
this(false, config);
}
private Application(final boolean singletonrun, final AnyValue config) {
this.singletonrun = singletonrun;
this.config = config;
final File root = new File(System.getProperty(RESNAME_APP_HOME));
this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime);
this.resourceFactory.register(RESNAME_APP_HOME, Path.class, root.toPath());
@@ -193,7 +193,7 @@ public final class Application {
properties.entrySet().stream().forEach(x -> {
x.setValue(x.getValue().toString().replace("${APP_HOME}", rootpath));
});
if (properties.getProperty("java.util.logging.FileHandler.formatter") == null) {
properties.setProperty("java.util.logging.FileHandler.formatter", LogFileHandler.LoggingFormater.class.getName());
}
@@ -275,27 +275,31 @@ public final class Application {
this.transportExecutor = transportExec;
this.transportChannelGroup = transportGroup;
}
public ResourceFactory getResourceFactory() {
return resourceFactory;
}
public WatchFactory getWatchFactory() {
return watchFactory;
}
public List<NodeServer> getNodeServers() {
return new ArrayList<>(servers);
}
public File getHome() {
return home;
}
public long getStartTime() {
return startTime;
}
private void initLogging() {
}
public void init() throws Exception {
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "" + Runtime.getRuntime().availableProcessors() * 4);
System.setProperty("convert.bson.tiny", "true");
@@ -304,7 +308,7 @@ public final class Application {
System.setProperty("convert.json.pool.size", "128");
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
System.setProperty("convert.json.writer.buffer.defsize", "4096");
File persist = new File(this.home, "conf/persistence.xml");
final String homepath = this.home.getCanonicalPath();
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
@@ -357,7 +361,7 @@ public final class Application {
this.resourceFactory.register(JsonFactory.root().getConvert());
initResources();
}
private void initResources() throws Exception {
//-------------------------------------------------------------------------
final AnyValue resources = config.getAnyValue("resources");
@@ -386,14 +390,14 @@ public final class Application {
}
//------------------------------------------------------------------------
}
private void startSelfServer() throws Exception {
final Application application = this;
new Thread() {
{
setName("Application-Control-Thread");
}
@Override
public void run() {
try {
@@ -451,7 +455,7 @@ public final class Application {
}
}.start();
}
private void sendCommand(String command) throws Exception {
final DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(true);
@@ -484,15 +488,18 @@ public final class Application {
throw e;
}
}
public void start() throws Exception {
final AnyValue[] entrys = config.getAnyValues("server");
CountDownLatch timecd = new CountDownLatch(entrys.length);
final List<AnyValue> sncps = new ArrayList<>();
final List<AnyValue> others = new ArrayList<>();
final List<AnyValue> watchs = new ArrayList<>();
for (final AnyValue entry : entrys) {
if (entry.getValue("protocol", "").toUpperCase().startsWith("SNCP")) {
sncps.add(entry);
} else if (entry.getValue("protocol", "").toUpperCase().startsWith("WATCH")) {
watchs.add(entry);
} else {
others.add(entry);
}
@@ -502,11 +509,12 @@ public final class Application {
runServers(timecd, sncps); //必须确保sncp都启动后再启动其他协议
runServers(timecd, others);
runServers(timecd, watchs); //必须在所有server都启动后再启动
timecd.await();
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms");
if (!singletonrun) this.serversLatch.await();
}
@SuppressWarnings("unchecked")
private void runServers(CountDownLatch timecd, final List<AnyValue> serconfs) throws Exception {
this.servicecdl = new CountDownLatch(serconfs.size());
@@ -520,7 +528,7 @@ public final class Application {
setName(serconf.getValue("protocol", "Server").toUpperCase() + "-" + host + ":" + serconf.getIntValue("port") + "-Thread");
this.setDaemon(true);
}
@Override
public void run() {
try {
@@ -530,13 +538,22 @@ public final class Application {
NodeServer server = null;
if ("SNCP".equals(protocol)) {
server = NodeSncpServer.createNodeServer(Application.this, serconf);
} else if ("WATCH".equalsIgnoreCase(protocol)) {
DefaultAnyValue serconf2 = (DefaultAnyValue) serconf;
DefaultAnyValue rest = (DefaultAnyValue) serconf2.getAnyValue("rest");
if (rest == null) {
rest = new DefaultAnyValue();
serconf2.addValue("rest", rest);
}
rest.setValue("base", WatchServlet.class.getName());
server = new NodeWatchServer(Application.this, serconf);
} else if ("HTTP".equalsIgnoreCase(protocol)) {
server = new NodeHttpServer(Application.this, serconf);
} else {
if (!inited.get()) {
synchronized (nodeClasses) {
if (!inited.getAndSet(true)) { //加载自定义的协议SOCKS
ClassFilter profilter = new ClassFilter(NodeProtocol.class, NodeServer.class);
ClassFilter profilter = new ClassFilter(NodeProtocol.class, NodeServer.class, (Class[]) null);
ClassFilter.Loader.load(home, serconf.getValue("excludelibs", "").split(";"), profilter);
final Set<FilterEntry<NodeServer>> entrys = profilter.getFilterEntrys();
for (FilterEntry<NodeServer> entry : entrys) {
@@ -577,11 +594,11 @@ public final class Application {
}
sercdl.await();
}
public static <T extends Service> T singleton(Class<T> serviceClass) throws Exception {
return singleton("", serviceClass);
}
public static <T extends Service> T singleton(String name, Class<T> serviceClass) throws Exception {
if (serviceClass == null) throw new IllegalArgumentException("serviceClass is null");
final Application application = Application.create(true);
@@ -595,14 +612,14 @@ public final class Application {
if (serviceClass.isInterface()) throw new IllegalArgumentException("interface class not allowed");
throw new IllegalArgumentException(serviceClass.getName() + " maybe have zero not-final public method");
}
public static Application create(final boolean singleton) throws IOException {
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath();
System.setProperty(RESNAME_APP_HOME, home);
File appfile = new File(home, "conf/application.xml");
return new Application(singleton, load(new FileInputStream(appfile)));
}
public static void main(String[] args) throws Exception {
Utility.midnight(); //先初始化一下Utility
//运行主程序
@@ -624,7 +641,7 @@ public final class Application {
}
System.exit(0);
}
Set<String> findSncpGroups(Transport sameGroupTransport, Collection<Transport> diffGroupTransports) {
Set<String> gs = new HashSet<>();
if (sameGroupTransport != null) gs.add(sameGroupTransport.getName());
@@ -635,7 +652,7 @@ public final class Application {
}
return gs;
}
NodeSncpServer findNodeSncpServer(final InetSocketAddress sncpAddr) {
for (NodeServer node : servers) {
if (node.isSNCP() && sncpAddr.equals(node.getSncpAddress())) {
@@ -644,12 +661,12 @@ public final class Application {
}
return null;
}
GroupInfo findGroupInfo(String group) {
if (group == null) return null;
return globalGroups.get(group);
}
private void shutdown() throws Exception {
servers.stream().forEach((server) -> {
try {
@@ -660,7 +677,7 @@ public final class Application {
serversLatch.countDown();
}
});
for (DataSource source : dataSources) {
try {
source.getClass().getMethod("close").invoke(source);
@@ -683,7 +700,7 @@ public final class Application {
}
}
}
private static AnyValue load(final InputStream in0) {
final DefaultAnyValue any = new DefaultAnyValue();
try (final InputStream in = in0) {
@@ -697,7 +714,7 @@ public final class Application {
}
return any;
}
private static void load(final DefaultAnyValue any, final Node root) {
final String home = System.getProperty(RESNAME_APP_HOME);
NamedNodeMap nodes = root.getAttributes();
@@ -715,6 +732,6 @@ public final class Application {
load(sub, node);
any.addValue(node.getNodeName(), sub);
}
}
}

View File

@@ -40,6 +40,8 @@ public final class ClassFilter<T> {
private Class superClass; //符合的父类型。不为空时扫描结果的class必须是superClass的子类
private Class[] excludeSuperClasses; //不符合的父类型。
private Class<? extends Annotation> annotationClass;//符合的注解。不为空时扫描结果的class必须包含该注解
private Pattern[] includePatterns; //符合的classname正则表达式
@@ -56,18 +58,19 @@ public final class ClassFilter<T> {
private AnyValue conf; //基本配置信息, 当符合条件时将conf的属性赋值到FilterEntry中去。
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass) {
this(annotationClass, superClass, null);
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses) {
this(annotationClass, superClass, excludeSuperClasses, null);
}
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass, AnyValue conf) {
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass, Class[] excludeSuperClasses, AnyValue conf) {
this.annotationClass = annotationClass;
this.superClass = superClass;
this.excludeSuperClasses = excludeSuperClasses;
this.conf = conf;
}
public static ClassFilter create(String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) {
ClassFilter filter = new ClassFilter(null, null);
public static ClassFilter create(Class[] excludeSuperClasses, String includeregs, String excluderegs, Set<String> includeValues, Set<String> excludeValues) {
ClassFilter filter = new ClassFilter(null, null, excludeSuperClasses);
filter.setIncludePatterns(includeregs == null ? null : includeregs.split(";"));
filter.setExcludePatterns(excluderegs == null ? null : excluderegs.split(";"));
filter.setPrivilegeIncludes(includeValues);
@@ -247,7 +250,13 @@ public final class ClassFilter<T> {
public boolean accept(AnyValue property, Class clazz, boolean autoscan) {
if (this.refused || !Modifier.isPublic(clazz.getModifiers())) return false;
if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) return false;
return superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz));
boolean rs = superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz));
if (rs && this.excludeSuperClasses != null && this.excludeSuperClasses.length > 0) {
for (Class c : this.excludeSuperClasses) {
if (c != null && (clazz == c || clazz.isAssignableFrom(c))) return false;
}
}
return rs;
}
public static Pattern[] toPattern(String[] regs) {
@@ -269,6 +278,18 @@ public final class ClassFilter<T> {
this.superClass = superClass;
}
public Class getSuperClass() {
return superClass;
}
public Class[] getExcludeSuperClasses() {
return excludeSuperClasses;
}
public void setExcludeSuperClasses(Class[] excludeSuperClasses) {
this.excludeSuperClasses = excludeSuperClasses;
}
public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
this.annotationClass = annotationClass;
}
@@ -293,10 +314,6 @@ public final class ClassFilter<T> {
return annotationClass;
}
public Class getSuperClass() {
return superClass;
}
public boolean isRefused() {
return refused;
}

View File

@@ -5,8 +5,10 @@
*/
package org.redkale.boot;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.net.InetSocketAddress;
import java.nio.file.WatchService;
import java.util.*;
import java.util.logging.Level;
import javax.annotation.Resource;
@@ -17,6 +19,7 @@ import org.redkale.net.sncp.Sncp;
import org.redkale.service.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*;
import org.redkale.watch.WatchServlet;
/**
* HTTP Server节点的配置Server
@@ -50,7 +53,12 @@ public class NodeHttpServer extends NodeServer {
@Override
protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, HttpServlet.class, null, "servlets", "servlet");
return createClassFilter(null, WebServlet.class, HttpServlet.class, new Class[]{WatchServlet.class}, null, "servlets", "servlet");
}
@Override
protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, Service.class, new Class[]{WatchService.class}, Annotation.class, "services", "service");
}
@Override
@@ -101,6 +109,7 @@ public class NodeHttpServer extends NodeServer {
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
for (FilterEntry<? extends Servlet> en : list) {
Class<HttpServlet> clazz = (Class<HttpServlet>) en.getType();
if (WatchServlet.class.isAssignableFrom(clazz)) continue; //给Watch服务使用
if (Modifier.isAbstract(clazz.getModifiers())) continue;
WebServlet ws = clazz.getAnnotation(WebServlet.class);
if (ws == null || ws.value().length == 0) continue;
@@ -159,7 +168,7 @@ public class NodeHttpServer extends NodeServer {
}
}
final ClassFilter restFilter = ClassFilter.create(restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
final ClassFilter restFilter = ClassFilter.create(null, restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
super.interceptorServices.forEach((service) -> {
final Class stype = Sncp.getServiceType(service);
@@ -172,6 +181,7 @@ public class NodeHttpServer extends NodeServer {
if (!restFilter.accept(stypename)) return;
HttpServlet servlet = httpServer.addRestServlet(name, stype, service, baseServletClass, prefix, (AnyValue) null);
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest(threadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
if (ss != null) {

View File

@@ -63,7 +63,7 @@ public abstract class NodeServer {
protected final Server server;
//当前Server的SNCP协议的组
private String sncpGroup = null;
protected String sncpGroup = null;
//SNCP服务的地址 非SNCP为null
private InetSocketAddress sncpAddress;
@@ -492,12 +492,12 @@ public abstract class NodeServer {
protected abstract ClassFilter<Servlet> createServletClassFilter();
protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, Service.class, Annotation.class, "services", "service");
return createClassFilter(this.sncpGroup, null, Service.class, null, Annotation.class, "services", "service");
}
protected ClassFilter createClassFilter(final String localGroup, Class<? extends Annotation> ref,
Class inter, Class<? extends Annotation> ref2, String properties, String property) {
ClassFilter cf = new ClassFilter(ref, inter, null);
Class inter, Class[] excludeSuperClasses, Class<? extends Annotation> ref2, String properties, String property) {
ClassFilter cf = new ClassFilter(ref, inter, excludeSuperClasses, null);
if (properties == null && properties == null) return cf;
if (this.serverConf == null) return cf;
AnyValue[] proplist = this.serverConf.getAnyValues(properties);
@@ -515,7 +515,7 @@ public abstract class NodeServer {
prop = new AnyValue.DefaultAnyValue();
prop.addValue("groups", sc);
}
ClassFilter filter = new ClassFilter(ref, inter, prop);
ClassFilter filter = new ClassFilter(ref, inter, excludeSuperClasses, prop);
for (AnyValue av : list.getAnyValues(property)) { // <service> 或 <servlet> 节点
final AnyValue[] items = av.getAnyValues("property");
if (av instanceof DefaultAnyValue && items.length > 0) { //存在 <property>节点

View File

@@ -0,0 +1,35 @@
/*
* 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.boot;
import java.lang.annotation.Annotation;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.service.Service;
import org.redkale.util.AnyValue;
import org.redkale.watch.*;
/**
*
* @author zhangjx
*/
@NodeProtocol({"WATCH"})
public class NodeWatchServer extends NodeHttpServer {
public NodeWatchServer(Application application, AnyValue serconf) {
super(application, serconf);
}
@Override
protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service");
}
@Override
protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet");
}
}

View File

@@ -39,6 +39,50 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
protected final Map<String, Class> allMapStrings = new HashMap<>();
private final Object excludeLock = new Object();
private Map<String, Predicate<String>> excludeUrlMaps; //禁用的URL的正则表达式, 必须与 excludeUrlPredicates 保持一致
private Predicate<String>[] excludeUrlPredicates; //禁用的URL的Predicate, 必须与 excludeUrlMaps 保持一致
public void addExcludeUrlReg(final String urlreg) {
if (urlreg == null || urlreg.isEmpty()) return;
synchronized (excludeLock) {
if (excludeUrlMaps != null && excludeUrlMaps.containsKey(urlreg)) return;
if (excludeUrlMaps == null) excludeUrlMaps = new HashMap<>();
Predicate<String> predicate = Pattern.compile(urlreg).asPredicate();
excludeUrlMaps.put(urlreg, predicate);
excludeUrlPredicates = Utility.append(excludeUrlPredicates, predicate);
}
}
public void removeExcludeUrlReg(final String urlreg) {
if (urlreg == null || urlreg.isEmpty()) return;
synchronized (excludeLock) {
if (excludeUrlMaps == null || excludeUrlPredicates == null || !excludeUrlMaps.containsKey(urlreg)) return;
Predicate<String> predicate = excludeUrlMaps.get(urlreg);
excludeUrlMaps.remove(urlreg);
int index = -1;
for (int i = 0; i < excludeUrlPredicates.length; i++) {
if (excludeUrlPredicates[i] == predicate) {
index = i;
break;
}
}
if (index > -1) {
if (excludeUrlPredicates.length == 1) {
excludeUrlPredicates = null;
} else {
int newlen = excludeUrlPredicates.length - 1;
Predicate[] news = new Predicate[newlen];
System.arraycopy(excludeUrlPredicates, 0, news, 0, index);
System.arraycopy(excludeUrlPredicates, index + 1, news, index, newlen - index);
excludeUrlPredicates = news;
}
}
}
}
@Override
public void init(HttpContext context, AnyValue config) {
Collection<HttpServlet> servlets = getServlets();
@@ -83,6 +127,19 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
public void execute(HttpRequest request, HttpResponse response) throws IOException {
try {
final String uri = request.getRequestURI();
boolean forbid = false;
if (excludeUrlPredicates != null && excludeUrlPredicates.length > 0) {
for (Predicate<String> predicate : excludeUrlPredicates) {
if (predicate != null && predicate.test(uri)) {
forbid = true;
break;
}
}
}
if (forbid) {
response.finish(403, response.getHttpCode(403));
return;
}
Servlet<HttpContext, HttpRequest, HttpResponse> servlet = null;
if (request.isWebSocket()) {
servlet = wsmappings.get(uri);

View File

@@ -23,7 +23,7 @@ import org.redkale.watch.WatchFactory;
*
* @author zhangjx
*/
public final class HttpServer extends Server<String, HttpContext, HttpRequest, HttpResponse, HttpServlet> {
public class HttpServer extends Server<String, HttpContext, HttpRequest, HttpResponse, HttpServlet> {
public HttpServer() {
this(System.currentTimeMillis(), null);
@@ -139,6 +139,7 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
}
final boolean first = servlet == null;
if (servlet == null) servlet = Rest.createRestServlet(baseServletClass, serviceType);
if (servlet == null) return null; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
try { //若提供动态变更Service服务功能则改Rest服务无法做出相应更新
Field field = servlet.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME);
field.setAccessible(true);
@@ -258,4 +259,21 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
return httpcontext;
}
/**
* 增加可以屏蔽的URL正则表达式
*
* @param urlreg URL正则表达式
*/
public void addExcludeUrlReg(final String urlreg) {
((HttpPrepareServlet) this.prepare).addExcludeUrlReg(urlreg);
}
/**
* 删除可以屏蔽的URL正则表达式
*
* @param urlreg URL正则表达式
*/
public void removeExcludeUrlReg(final String urlreg) {
((HttpPrepareServlet) this.prepare).removeExcludeUrlReg(urlreg);
}
}

View File

@@ -135,7 +135,7 @@ public final class Rest {
final Class userType = hut == null ? Object.class : hut.value();
final String supDynName = baseServletClass.getName().replace('.', '/');
final RestService controller = serviceType.getAnnotation(RestService.class);
if (controller != null && controller.ignore()) return null; //标记为ignore=true不创建Servlet
if (controller != null && controller.ignore()) throw new RuntimeException(baseServletClass + " is ignore Rest Service Class"); //标记为ignore=true不创建Servlet
ClassLoader loader = Sncp.class.getClassLoader();
String newDynName = serviceTypeInternalName.substring(0, serviceTypeInternalName.lastIndexOf('/') + 1) + "_Dyn" + serviceType.getSimpleName().replaceAll("Service.*$", "") + "RestServlet";

View File

@@ -23,7 +23,7 @@ import org.redkale.watch.*;
* @author zhangjx
*/
@SuppressWarnings("unchecked")
public final class SncpServer extends Server<DLong, SncpContext, SncpRequest, SncpResponse, SncpServlet> {
public class SncpServer extends Server<DLong, SncpContext, SncpRequest, SncpResponse, SncpServlet> {
public SncpServer() {
this(System.currentTimeMillis(), null);

View File

@@ -41,6 +41,8 @@ public final class ResourceFactory {
private static final ResourceFactory instance = new ResourceFactory(null);
private final List<WeakReference<ResourceFactory>> chidren = new CopyOnWriteArrayList<>();
private final ConcurrentHashMap<Type, ResourceLoader> loadermap = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, ConcurrentHashMap<String, ResourceEntry>> store = new ConcurrentHashMap();
@@ -54,7 +56,18 @@ public final class ResourceFactory {
}
public ResourceFactory createChild() {
return new ResourceFactory(this);
ResourceFactory child = new ResourceFactory(this);
this.chidren.add(new WeakReference<>(child));
return child;
}
public List<ResourceFactory> getChildren() {
List<ResourceFactory> result = new ArrayList<>();
for (WeakReference<ResourceFactory> ref : chidren) {
ResourceFactory rf = ref.get();
if (rf != null) result.add(rf);
}
return result;
}
public void release() {

View File

@@ -13,13 +13,17 @@ import java.util.function.LongSupplier;
/**
*
* <p> 详情见: https://redkale.org
* <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 WatchFactory parent;
@@ -29,7 +33,9 @@ public final class WatchFactory {
}
public void register(WatchNode bean) {
if (bean != null) beans.add(new WeakReference<>(bean));
if (bean == null) return;
checkName(bean.getName());
beans.add(new WeakReference<>(bean));
}
public static WatchFactory root() {
@@ -37,7 +43,27 @@ public final class WatchFactory {
}
public WatchFactory createChild() {
return new WatchFactory(this);
WatchFactory child = new WatchFactory(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) {
@@ -74,6 +100,12 @@ public final class WatchFactory {
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 //");
}
}
public boolean inject(final Object src) {
return inject(src, new ArrayList<>());
}

View File

@@ -0,0 +1,16 @@
/*
* 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 org.redkale.service.*;
/**
*
* @author zhangjx
*/
public interface WatchService extends Service {
}

View File

@@ -0,0 +1,17 @@
/*
* 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 org.redkale.net.http.HttpServlet;
/**
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
public class WatchServlet extends HttpServlet {
}