1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package net.anyflow.lannister.plugin;
18
19 import java.io.File;
20 import java.net.MalformedURLException;
21 import java.net.URISyntaxException;
22 import java.net.URL;
23 import java.net.URLClassLoader;
24 import java.security.CodeSource;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.stream.Stream;
28
29 import org.reflections.Reflections;
30 import org.reflections.scanners.SubTypesScanner;
31
32 import com.google.common.collect.Lists;
33 import com.google.common.collect.Maps;
34
35 import net.anyflow.lannister.Application;
36
37 public class Plugins {
38 private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(Plugins.class);
39
40 public static final Plugins INSTANCE = new Plugins();
41
42 private Map<Class<? extends Plugin>, Plugin> plugins;
43
44 private Plugins() {
45 plugins = Maps.newHashMap();
46
47 plugins.put(Authenticator.class, new DefaultAuthenticator());
48 plugins.put(Authorizer.class, new DefaultAuthorizer());
49 plugins.put(ServiceChecker.class, new DefaultServiceChecker());
50 plugins.put(ConnectEventListener.class, new DefaultConnectEventListener());
51 plugins.put(DisconnectEventListener.class, new DefaultDisconnectEventListener());
52 plugins.put(PublishEventListener.class, new DefaultPublishEventListener());
53 plugins.put(DeliveredEventListener.class, new DefaultDeliveredEventListener());
54 plugins.put(SubscribeEventListener.class, new DefaultSubscribeEventListener());
55 plugins.put(UnsubscribeEventListener.class, new DefaultUnsubscribeEventListener());
56
57 load();
58 }
59
60 private void load() {
61 URLClassLoader classLoader = null;
62 try {
63 classLoader = new URLClassLoader(pluginJarUrls(), Plugins.class.getClassLoader());
64 }
65 catch (MalformedURLException e) {
66 logger.error(e.getMessage(), e);
67 }
68
69 Reflections reflections = new Reflections(classLoader, new SubTypesScanner(false));
70
71 load(Authenticator.class, reflections.getSubTypesOf(Authenticator.class).stream()
72 .filter(p -> !p.equals(DefaultAuthenticator.class)));
73 load(Authorizer.class,
74 reflections.getSubTypesOf(Authorizer.class).stream().filter(p -> !p.equals(DefaultAuthorizer.class)));
75 load(ServiceChecker.class, reflections.getSubTypesOf(ServiceChecker.class).stream()
76 .filter(p -> !p.equals(DefaultServiceChecker.class)));
77 load(ConnectEventListener.class, reflections.getSubTypesOf(ConnectEventListener.class).stream()
78 .filter(p -> !p.equals(DefaultConnectEventListener.class)));
79 load(DisconnectEventListener.class, reflections.getSubTypesOf(DisconnectEventListener.class).stream()
80 .filter(p -> !p.equals(DefaultDisconnectEventListener.class)));
81 load(PublishEventListener.class, reflections.getSubTypesOf(PublishEventListener.class).stream()
82 .filter(p -> !p.equals(DefaultPublishEventListener.class)));
83 load(DeliveredEventListener.class, reflections.getSubTypesOf(DeliveredEventListener.class).stream()
84 .filter(p -> !p.equals(DefaultDeliveredEventListener.class)));
85 load(SubscribeEventListener.class, reflections.getSubTypesOf(SubscribeEventListener.class).stream()
86 .filter(p -> !p.equals(DefaultSubscribeEventListener.class)));
87 load(UnsubscribeEventListener.class, reflections.getSubTypesOf(UnsubscribeEventListener.class).stream()
88 .filter(p -> !p.equals(DefaultUnsubscribeEventListener.class)));
89 }
90
91 @SuppressWarnings("unchecked")
92 public <T extends Plugin> T get(Class<T> clazz) {
93 return (T) plugins.get(clazz).clone();
94 }
95
96 @SuppressWarnings("unchecked")
97 public <T extends Plugin> T put(Class<T> clazz, T source) {
98 return (T) plugins.put(clazz, source);
99 }
100
101 private String appRootPath() {
102 CodeSource codeSource = Application.class.getProtectionDomain().getCodeSource();
103
104 try {
105 return new File(codeSource.getLocation().toURI().getPath()).getParentFile().getPath();
106 }
107 catch (URISyntaxException e) {
108 logger.error(e.getMessage(), e);
109 return null;
110 }
111 }
112
113 private URL[] pluginJarUrls() throws MalformedURLException {
114 File dir = new File(appRootPath() + "/plugin/");
115 File[] files = dir.listFiles();
116 if (files != null) {
117 List<URL> ret = Lists.newArrayList();
118
119 for (File item : files) {
120 ret.add(item.toURI().toURL());
121 }
122
123 return ret.toArray(new URL[0]);
124 }
125 else {
126 return new URL[0];
127 }
128 }
129
130 private <T extends Plugin> void load(Class<T> clazz, Stream<Class<? extends T>> source) {
131 Class<? extends T> plugin = source.findAny().orElse(null);
132 if (plugin == null) { return; }
133
134 try {
135 T instance = plugin.newInstance();
136 plugins.put(clazz, instance);
137 logger.info("Plugin loaded [{}]", instance.getClass().getName());
138 }
139 catch (InstantiationException | IllegalAccessException e) {
140 logger.error(e.getMessage(), e);
141 }
142 }
143 }