From 853e823a8d03dac0047805537783811de4b1bbdb Mon Sep 17 00:00:00 2001 From: Redkale <22250530@qq.com> Date: Sun, 14 May 2017 11:34:15 +0800 Subject: [PATCH] --- src/org/redkale/boot/ApiDocsService.java | 5 +- src/org/redkale/boot/Application.java | 83 +++++++++++-------- src/org/redkale/boot/ClassFilter.java | 37 ++++++--- src/org/redkale/boot/NodeHttpServer.java | 14 +++- src/org/redkale/boot/NodeServer.java | 10 +-- src/org/redkale/boot/NodeWatchServer.java | 35 ++++++++ .../redkale/net/http/HttpPrepareServlet.java | 57 +++++++++++++ src/org/redkale/net/http/HttpServer.java | 20 ++++- src/org/redkale/net/http/Rest.java | 2 +- src/org/redkale/net/sncp/SncpServer.java | 2 +- src/org/redkale/util/ResourceFactory.java | 15 +++- src/org/redkale/watch/WatchFactory.java | 38 ++++++++- src/org/redkale/watch/WatchService.java | 16 ++++ src/org/redkale/watch/WatchServlet.java | 17 ++++ 14 files changed, 290 insertions(+), 61 deletions(-) create mode 100644 src/org/redkale/boot/NodeWatchServer.java create mode 100644 src/org/redkale/watch/WatchService.java create mode 100644 src/org/redkale/watch/WatchServlet.java diff --git a/src/org/redkale/boot/ApiDocsService.java b/src/org/redkale/boot/ApiDocsService.java index 370f64d00..d827862d6 100644 --- a/src/org/redkale/boot/ApiDocsService.java +++ b/src/org/redkale/boot/ApiDocsService.java @@ -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全局对象 diff --git a/src/org/redkale/boot/Application.java b/src/org/redkale/boot/Application.java index 3da64eb32..c1bf47878 100644 --- a/src/org/redkale/boot/Application.java +++ b/src/org/redkale/boot/Application.java @@ -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 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 sncps = new ArrayList<>(); final List others = new ArrayList<>(); + final List 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 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> entrys = profilter.getFilterEntrys(); for (FilterEntry entry : entrys) { @@ -577,11 +594,11 @@ public final class Application { } sercdl.await(); } - + public static T singleton(Class serviceClass) throws Exception { return singleton("", serviceClass); } - + public static T singleton(String name, Class 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 findSncpGroups(Transport sameGroupTransport, Collection diffGroupTransports) { Set 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); } - + } } diff --git a/src/org/redkale/boot/ClassFilter.java b/src/org/redkale/boot/ClassFilter.java index 5ee245202..d2931f733 100644 --- a/src/org/redkale/boot/ClassFilter.java +++ b/src/org/redkale/boot/ClassFilter.java @@ -40,6 +40,8 @@ public final class ClassFilter { private Class superClass; //符合的父类型。不为空时,扫描结果的class必须是superClass的子类 + private Class[] excludeSuperClasses; //不符合的父类型。 + private Class annotationClass;//符合的注解。不为空时,扫描结果的class必须包含该注解 private Pattern[] includePatterns; //符合的classname正则表达式 @@ -56,18 +58,19 @@ public final class ClassFilter { private AnyValue conf; //基本配置信息, 当符合条件时将conf的属性赋值到FilterEntry中去。 - public ClassFilter(Class annotationClass, Class superClass) { - this(annotationClass, superClass, null); + public ClassFilter(Class annotationClass, Class superClass, Class[] excludeSuperClasses) { + this(annotationClass, superClass, excludeSuperClasses, null); } - public ClassFilter(Class annotationClass, Class superClass, AnyValue conf) { + public ClassFilter(Class 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 includeValues, Set excludeValues) { - ClassFilter filter = new ClassFilter(null, null); + public static ClassFilter create(Class[] excludeSuperClasses, String includeregs, String excluderegs, Set includeValues, Set 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 { 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 { 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 annotationClass) { this.annotationClass = annotationClass; } @@ -293,10 +314,6 @@ public final class ClassFilter { return annotationClass; } - public Class getSuperClass() { - return superClass; - } - public boolean isRefused() { return refused; } diff --git a/src/org/redkale/boot/NodeHttpServer.java b/src/org/redkale/boot/NodeHttpServer.java index f06ba2d3d..f66928ebc 100644 --- a/src/org/redkale/boot/NodeHttpServer.java +++ b/src/org/redkale/boot/NodeHttpServer.java @@ -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 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 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> ss = sb == null ? null : new ArrayList<>(); for (FilterEntry en : list) { Class clazz = (Class) 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) { diff --git a/src/org/redkale/boot/NodeServer.java b/src/org/redkale/boot/NodeServer.java index 8a27da39a..e3f51a741 100644 --- a/src/org/redkale/boot/NodeServer.java +++ b/src/org/redkale/boot/NodeServer.java @@ -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 createServletClassFilter(); protected ClassFilter 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 ref, - Class inter, Class ref2, String properties, String property) { - ClassFilter cf = new ClassFilter(ref, inter, null); + Class inter, Class[] excludeSuperClasses, Class 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)) { // 节点 final AnyValue[] items = av.getAnyValues("property"); if (av instanceof DefaultAnyValue && items.length > 0) { //存在 节点 diff --git a/src/org/redkale/boot/NodeWatchServer.java b/src/org/redkale/boot/NodeWatchServer.java new file mode 100644 index 000000000..ad2aaaa63 --- /dev/null +++ b/src/org/redkale/boot/NodeWatchServer.java @@ -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 createServiceClassFilter() { + return createClassFilter(this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service"); + } + + @Override + protected ClassFilter createServletClassFilter() { + return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet"); + } +} diff --git a/src/org/redkale/net/http/HttpPrepareServlet.java b/src/org/redkale/net/http/HttpPrepareServlet.java index 4c947beae..ea25463ac 100644 --- a/src/org/redkale/net/http/HttpPrepareServlet.java +++ b/src/org/redkale/net/http/HttpPrepareServlet.java @@ -39,6 +39,50 @@ public class HttpPrepareServlet extends PrepareServlet allMapStrings = new HashMap<>(); + private final Object excludeLock = new Object(); + + private Map> excludeUrlMaps; //禁用的URL的正则表达式, 必须与 excludeUrlPredicates 保持一致 + + private Predicate[] 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 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 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 servlets = getServlets(); @@ -83,6 +127,19 @@ public class HttpPrepareServlet extends PrepareServlet 0) { + for (Predicate predicate : excludeUrlPredicates) { + if (predicate != null && predicate.test(uri)) { + forbid = true; + break; + } + } + } + if (forbid) { + response.finish(403, response.getHttpCode(403)); + return; + } Servlet servlet = null; if (request.isWebSocket()) { servlet = wsmappings.get(uri); diff --git a/src/org/redkale/net/http/HttpServer.java b/src/org/redkale/net/http/HttpServer.java index b7c3f8daa..760b18409 100644 --- a/src/org/redkale/net/http/HttpServer.java +++ b/src/org/redkale/net/http/HttpServer.java @@ -23,7 +23,7 @@ import org.redkale.watch.WatchFactory; * * @author zhangjx */ -public final class HttpServer extends Server { +public class HttpServer extends Server { public HttpServer() { this(System.currentTimeMillis(), null); @@ -139,6 +139,7 @@ public final class HttpServer extends Server { +public class SncpServer extends Server { public SncpServer() { this(System.currentTimeMillis(), null); diff --git a/src/org/redkale/util/ResourceFactory.java b/src/org/redkale/util/ResourceFactory.java index 9052e283f..7dee15e03 100644 --- a/src/org/redkale/util/ResourceFactory.java +++ b/src/org/redkale/util/ResourceFactory.java @@ -41,6 +41,8 @@ public final class ResourceFactory { private static final ResourceFactory instance = new ResourceFactory(null); + private final List> chidren = new CopyOnWriteArrayList<>(); + private final ConcurrentHashMap loadermap = new ConcurrentHashMap(); private final ConcurrentHashMap> 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 getChildren() { + List result = new ArrayList<>(); + for (WeakReference ref : chidren) { + ResourceFactory rf = ref.get(); + if (rf != null) result.add(rf); + } + return result; } public void release() { diff --git a/src/org/redkale/watch/WatchFactory.java b/src/org/redkale/watch/WatchFactory.java index 2ad0927fd..0a7546cd2 100644 --- a/src/org/redkale/watch/WatchFactory.java +++ b/src/org/redkale/watch/WatchFactory.java @@ -13,13 +13,17 @@ import java.util.function.LongSupplier; /** * - *

详情见: https://redkale.org + *

+ * 详情见: https://redkale.org + * * @author zhangjx */ public final class WatchFactory { private static final WatchFactory instance = new WatchFactory(null); + private final List> chidren = new CopyOnWriteArrayList<>(); + private final List> 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 getChildren() { + List result = new ArrayList<>(); + for (WeakReference ref : chidren) { + WatchFactory rf = ref.get(); + if (rf != null) result.add(rf); + } + return result; + } + + public List getWatchNodes() { + List result = new ArrayList<>(); + for (WeakReference 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<>()); } diff --git a/src/org/redkale/watch/WatchService.java b/src/org/redkale/watch/WatchService.java new file mode 100644 index 000000000..520bcdddc --- /dev/null +++ b/src/org/redkale/watch/WatchService.java @@ -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 { + +} diff --git a/src/org/redkale/watch/WatchServlet.java b/src/org/redkale/watch/WatchServlet.java new file mode 100644 index 000000000..11f5b8360 --- /dev/null +++ b/src/org/redkale/watch/WatchServlet.java @@ -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; + +/** + * + *

详情见: https://redkale.org + * @author zhangjx + */ +public class WatchServlet extends HttpServlet { + +}