This commit is contained in:
@@ -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全局对象
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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>节点
|
||||
|
||||
35
src/org/redkale/boot/NodeWatchServer.java
Normal file
35
src/org/redkale/boot/NodeWatchServer.java
Normal 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");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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<>());
|
||||
}
|
||||
|
||||
16
src/org/redkale/watch/WatchService.java
Normal file
16
src/org/redkale/watch/WatchService.java
Normal 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 {
|
||||
|
||||
}
|
||||
17
src/org/redkale/watch/WatchServlet.java
Normal file
17
src/org/redkale/watch/WatchServlet.java
Normal 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 {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user