From 1cc63fc12f4779054e45f291185581c81c6faf4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9C=B0=E5=B9=B3=E7=BA=BF?= <22250530@qq.com> Date: Wed, 16 Sep 2015 10:53:45 +0800 Subject: [PATCH] --- src/com/wentch/redkale/boot/Application.java | 26 ++++++ src/com/wentch/redkale/boot/ClassFilter.java | 87 ++++++++++++++----- .../wentch/redkale/boot/NodeHttpServer.java | 1 + src/com/wentch/redkale/boot/NodeProtocol.java | 19 ++++ src/com/wentch/redkale/boot/NodeServer.java | 8 ++ .../wentch/redkale/boot/NodeSncpServer.java | 1 + .../redkale/net/icep/BindingIcepServlet.java | 1 - .../redkale/net/icep/IcepPrepareServlet.java | 7 +- .../wentch/redkale/net/icep/IcepServer.java | 16 ++-- .../redkale/net/icep/NodeIcepServer.java | 72 +++++++++++++++ 10 files changed, 208 insertions(+), 30 deletions(-) create mode 100644 src/com/wentch/redkale/boot/NodeProtocol.java create mode 100644 src/com/wentch/redkale/net/icep/NodeIcepServer.java diff --git a/src/com/wentch/redkale/boot/Application.java b/src/com/wentch/redkale/boot/Application.java index 9a2a5f9ad..fdb954ba6 100644 --- a/src/com/wentch/redkale/boot/Application.java +++ b/src/com/wentch/redkale/boot/Application.java @@ -5,6 +5,7 @@ */ package com.wentch.redkale.boot; +import com.wentch.redkale.boot.ClassFilter.FilterEntry; import com.wentch.redkale.convert.bson.*; import com.wentch.redkale.convert.json.*; import com.wentch.redkale.net.*; @@ -21,6 +22,7 @@ import java.nio.channels.*; import java.nio.file.*; import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.atomic.*; import java.util.logging.*; import javax.xml.parsers.*; import org.w3c.dom.*; @@ -391,6 +393,8 @@ public final class Application { private void runServers(CountDownLatch timecd, final List serconfs) throws Exception { this.servicecdl = new CountDownLatch(serconfs.size()); CountDownLatch sercdl = new CountDownLatch(serconfs.size()); + final AtomicBoolean inited = new AtomicBoolean(false); + final Map> nodeClasses = new HashMap<>(); for (final AnyValue serconf : serconfs) { Thread thread = new Thread() { { @@ -410,6 +414,28 @@ public final class Application { server = new NodeSncpServer(Application.this, serconf); } else if ("HTTP".equalsIgnoreCase(protocol)) { server = new NodeHttpServer(Application.this, serconf); + } else { + if (!inited.get()) { + synchronized (nodeClasses) { + if (!inited.get()) { + inited.set(true); + ClassFilter profilter = new ClassFilter(NodeProtocol.class, NodeServer.class); + ClassFilter.Loader.load(home, profilter); + final Set> entrys = profilter.getFilterEntrys(); + for (FilterEntry entry : entrys) { + final Class type = entry.getType(); + NodeProtocol pros = type.getAnnotation(NodeProtocol.class); + for (String p : pros.value()) { + final Class old = nodeClasses.get(p); + if (old != null && old != type) throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")"); + nodeClasses.put(p, type); + } + } + } + } + } + Class nodeClass = nodeClasses.get(protocol); + if (nodeClass != null) server = NodeServer.create(nodeClass, Application.this, serconf); } if (server == null) { logger.log(Level.SEVERE, "Not found Server Class for protocol({0})", serconf.getValue("protocol")); diff --git a/src/com/wentch/redkale/boot/ClassFilter.java b/src/com/wentch/redkale/boot/ClassFilter.java index f7923d838..e850d01de 100644 --- a/src/com/wentch/redkale/boot/ClassFilter.java +++ b/src/com/wentch/redkale/boot/ClassFilter.java @@ -14,6 +14,7 @@ import java.lang.annotation.*; import java.lang.reflect.*; import java.net.*; import java.util.*; +import java.util.concurrent.*; import java.util.jar.*; import java.util.logging.*; import java.util.regex.*; @@ -322,6 +323,12 @@ public final class ClassFilter { protected static final Logger logger = Logger.getLogger(Loader.class.getName()); + protected static final ConcurrentMap> cache = new ConcurrentHashMap<>(); + + public static void close() { + cache.clear(); + } + /** * 加载当前线程的classpath扫描所有class进行过滤 *

@@ -346,33 +353,69 @@ public final class ClassFilter { List files = new ArrayList<>(); boolean debug = logger.isLoggable(Level.FINEST); StringBuilder debugstr = new StringBuilder(); - for (URL url : urljares) { - try (JarFile jar = new JarFile(URLDecoder.decode(url.getFile(), "UTF-8"))) { - Enumeration it = jar.entries(); - while (it.hasMoreElements()) { - String entryname = it.nextElement().getName().replace('/', '.'); - if (entryname.endsWith(".class") && entryname.indexOf('$') < 0) { - String classname = entryname.substring(0, entryname.length() - 6); - if (classname.startsWith("javax.") || classname.startsWith("org.") || classname.startsWith("com.mysql.")) continue; - if (debug) debugstr.append(classname).append("\r\n"); - for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname); + for (final URL url : urljares) { + Set classes = cache.get(url); + if (classes == null) { + synchronized (cache) { + if (cache.get(url) == null) { + classes = new CopyOnWriteArraySet<>(); + cache.put(url, classes); + } else { + classes = cache.get(url); + } + } + try (JarFile jar = new JarFile(URLDecoder.decode(url.getFile(), "UTF-8"))) { + Enumeration it = jar.entries(); + while (it.hasMoreElements()) { + String entryname = it.nextElement().getName().replace('/', '.'); + if (entryname.endsWith(".class") && entryname.indexOf('$') < 0) { + String classname = entryname.substring(0, entryname.length() - 6); + if (classname.startsWith("javax.") || classname.startsWith("org.") || classname.startsWith("com.mysql.")) continue; + classes.add(classname); + if (debug) debugstr.append(classname).append("\r\n"); + for (final ClassFilter filter : filters) { + if (filter != null) filter.filter(null, classname); + } } } } + } else { + for (String classname : classes) { + for (final ClassFilter filter : filters) { + if (filter != null) filter.filter(null, classname); + } + } } } - for (URL url : urlfiles) { - files.clear(); - File root = new File(url.getFile()); - String rootpath = root.getPath(); - loadClassFiles(exclude, root, files); - for (File f : files) { - String classname = f.getPath().substring(rootpath.length() + 1, f.getPath().length() - 6).replace(File.separatorChar, '.'); - if (classname.startsWith("javax.") || classname.startsWith("org.") || classname.startsWith("com.mysql.")) continue; - if (debug) debugstr.append(classname).append("\r\n"); - for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname); + for (final URL url : urlfiles) { + Set classes = cache.get(url); + if (classes == null) { + synchronized (cache) { + if (cache.get(url) == null) { + classes = new CopyOnWriteArraySet<>(); + cache.put(url, classes); + } else { + classes = cache.get(url); + } + } + files.clear(); + File root = new File(url.getFile()); + String rootpath = root.getPath(); + loadClassFiles(exclude, root, files); + for (File f : files) { + String classname = f.getPath().substring(rootpath.length() + 1, f.getPath().length() - 6).replace(File.separatorChar, '.'); + if (classname.startsWith("javax.") || classname.startsWith("org.") || classname.startsWith("com.mysql.")) continue; + classes.add(classname); + if (debug) debugstr.append(classname).append("\r\n"); + for (final ClassFilter filter : filters) { + if (filter != null) filter.filter(null, classname); + } + } + } else { + for (String classname : classes) { + for (final ClassFilter filter : filters) { + if (filter != null) filter.filter(null, classname); + } } } } diff --git a/src/com/wentch/redkale/boot/NodeHttpServer.java b/src/com/wentch/redkale/boot/NodeHttpServer.java index 6393617c1..40a945e83 100644 --- a/src/com/wentch/redkale/boot/NodeHttpServer.java +++ b/src/com/wentch/redkale/boot/NodeHttpServer.java @@ -27,6 +27,7 @@ import javax.annotation.*; * * @author zhangjx */ +@NodeProtocol({"HTTP", "HTTPS"}) public final class NodeHttpServer extends NodeServer { private final HttpServer httpServer; diff --git a/src/com/wentch/redkale/boot/NodeProtocol.java b/src/com/wentch/redkale/boot/NodeProtocol.java new file mode 100644 index 000000000..d1e9d9efd --- /dev/null +++ b/src/com/wentch/redkale/boot/NodeProtocol.java @@ -0,0 +1,19 @@ +/* + * 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 com.wentch.redkale.boot; + +import java.lang.annotation.*; + +/** + * + * @author zhangjx + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface NodeProtocol { + String[] value(); +} diff --git a/src/com/wentch/redkale/boot/NodeServer.java b/src/com/wentch/redkale/boot/NodeServer.java index f37f05683..9d8af0b1d 100644 --- a/src/com/wentch/redkale/boot/NodeServer.java +++ b/src/com/wentch/redkale/boot/NodeServer.java @@ -73,6 +73,14 @@ public abstract class NodeServer { this.fine = logger.isLoggable(Level.FINE); } + public static NodeServer create(Class clazz, Application application, AnyValue serconf) { + try { + return clazz.getConstructor(Application.class, AnyValue.class).newInstance(application, serconf); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + public void init(AnyValue config) throws Exception { this.nodeConf = config == null ? AnyValue.create() : config; if (isSNCP()) { // SNCP协议 diff --git a/src/com/wentch/redkale/boot/NodeSncpServer.java b/src/com/wentch/redkale/boot/NodeSncpServer.java index 0931f900b..dd491c7ba 100644 --- a/src/com/wentch/redkale/boot/NodeSncpServer.java +++ b/src/com/wentch/redkale/boot/NodeSncpServer.java @@ -15,6 +15,7 @@ import java.util.logging.*; * * @author zhangjx */ +@NodeProtocol({"SNCP"}) public final class NodeSncpServer extends NodeServer { private final SncpServer sncpServer; diff --git a/src/com/wentch/redkale/net/icep/BindingIcepServlet.java b/src/com/wentch/redkale/net/icep/BindingIcepServlet.java index 58504d43c..d288e6c17 100644 --- a/src/com/wentch/redkale/net/icep/BindingIcepServlet.java +++ b/src/com/wentch/redkale/net/icep/BindingIcepServlet.java @@ -15,7 +15,6 @@ import java.nio.*; * * @author zhangjx */ -@AutoLoad(false) public class BindingIcepServlet extends IcepServlet { @Override diff --git a/src/com/wentch/redkale/net/icep/IcepPrepareServlet.java b/src/com/wentch/redkale/net/icep/IcepPrepareServlet.java index e0bc2eca4..b50819af7 100644 --- a/src/com/wentch/redkale/net/icep/IcepPrepareServlet.java +++ b/src/com/wentch/redkale/net/icep/IcepPrepareServlet.java @@ -19,14 +19,17 @@ public class IcepPrepareServlet extends PrepareServlet servletmaps = new HashMap<>(); public IcepPrepareServlet() { - BindingIcepServlet servlet = new BindingIcepServlet(); - this.servletmaps.put(servlet.getRequestid(), new BindingIcepServlet()); } @Override public void init(Context context, AnyValue config) { } + public void addIcepServlet(IcepServlet servlet, AnyValue conf) { + servlet.conf = conf; + this.servletmaps.put(servlet.getRequestid(), servlet); + } + // 28.[00,03,00,08, 21,12,a4,42,45,6f,4e,77,4e,47,71,55,32,37,77,39, 00,19,00,04,11,00,00,00] @Override public void execute(IcepRequest request, IcepResponse response) throws IOException { diff --git a/src/com/wentch/redkale/net/icep/IcepServer.java b/src/com/wentch/redkale/net/icep/IcepServer.java index 43d9e118b..fb51e39e1 100644 --- a/src/com/wentch/redkale/net/icep/IcepServer.java +++ b/src/com/wentch/redkale/net/icep/IcepServer.java @@ -22,18 +22,20 @@ public final class IcepServer extends Server { public IcepServer() { this(System.currentTimeMillis(), null); } + /** - "content":"{\"cmd\":\"icecandidate\",\"candidate\":{\"candidate\":\"candidate:3791502225 1 tcp 1518214911 10.28.2.207 0 typ host tcptype active generation 0\",\"sdpMid\":\"video\",\"sdpMLineIndex\":1}}" - @param args - @throws Exception - */ + "content":"{\"cmd\":\"icecandidate\",\"candidate\":{\"candidate\":\"candidate:3791502225 1 tcp 1518214911 10.28.2.207 0 typ host tcptype active generation 0\",\"sdpMid\":\"video\",\"sdpMLineIndex\":1}}" + @param args + @throws Exception + */ public static void main(String[] args) throws Exception { DefaultAnyValue conf = new DefaultAnyValue(); conf.addValue("host", "10.28.2.207"); conf.addValue("port", "3478"); final CountDownLatch cdl = new CountDownLatch(1); final IcepServer server = new IcepServer(); - server.init(conf); + server.init(conf); + server.addIcepServlet(new BindingIcepServlet(), null); server.start(); cdl.await(); } @@ -47,6 +49,10 @@ public final class IcepServer extends Server { super.init(config); } + public void addIcepServlet(IcepServlet servlet, AnyValue conf) { + ((IcepPrepareServlet) this.prepare).addIcepServlet(servlet, conf); + } + @Override @SuppressWarnings("unchecked") protected Context createContext() { diff --git a/src/com/wentch/redkale/net/icep/NodeIcepServer.java b/src/com/wentch/redkale/net/icep/NodeIcepServer.java new file mode 100644 index 000000000..bb8c8cc50 --- /dev/null +++ b/src/com/wentch/redkale/net/icep/NodeIcepServer.java @@ -0,0 +1,72 @@ +/* + * 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 com.wentch.redkale.net.icep; + +import com.wentch.redkale.boot.*; +import com.wentch.redkale.boot.ClassFilter.FilterEntry; +import com.wentch.redkale.net.*; +import com.wentch.redkale.util.*; +import com.wentch.redkale.util.AnyValue.DefaultAnyValue; +import java.lang.reflect.*; +import java.net.*; +import java.util.logging.*; + +/** + * + * @author zhangjx + */ +@NodeProtocol({"ICEP"}) +public class NodeIcepServer extends NodeServer { + + private final IcepServer icepServer; + + public NodeIcepServer(Application application, AnyValue serconf) { + super(application, application.getResourceFactory().createChild(), createServer(application, serconf)); + this.icepServer = (IcepServer) server; + } + + private static Server createServer(Application application, AnyValue serconf) { + return new IcepServer(application.getStartTime(), application.getWatchFactory()); + } + + @Override + public InetSocketAddress getSocketAddress() { + return icepServer == null ? null : icepServer.getSocketAddress(); + } + + @Override + protected ClassFilter createServletClassFilter() { + return createClassFilter(null, null, IcepServlet.class, null, "servlets", "servlet"); + } + + @Override + protected void loadServlet(ClassFilter servletFilter) throws Exception { + if (icepServer != null) loadIcepServlet(this.nodeConf.getAnyValue("servlets"), servletFilter); + } + + protected void loadIcepServlet(final AnyValue conf, ClassFilter filter) throws Exception { + final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null; + final String threadName = "[" + Thread.currentThread().getName() + "] "; + for (FilterEntry en : filter.getFilterEntrys()) { + Class clazz = (Class) en.getType(); + if (Modifier.isAbstract(clazz.getModifiers())) continue; + final IcepServlet servlet = clazz.newInstance(); + factory.inject(servlet); + DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty(); + this.icepServer.addIcepServlet(servlet, servletConf); + if (sb != null) sb.append(threadName).append(" Loaded ").append(clazz.getName()).append(" --> ").append(format(servlet.getRequestid())).append(LINE_SEPARATOR); + } + if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString()); + } + + private static String format(short value) { + String str = Integer.toHexString(value); + if (str.length() == 1) return "0x000" + str; + if (str.length() == 2) return "0x00" + str; + if (str.length() == 3) return "0x0" + str; + return "0x" + str; + } +}