Skip to content

Commit caab1cf

Browse files
committed
1.x: add shorter RxJavaPlugin class lookup approach.
1 parent 3e2b3b1 commit caab1cf

File tree

2 files changed

+76
-23
lines changed

2 files changed

+76
-23
lines changed

src/main/java/rx/plugins/RxJavaPlugins.java

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package rx.plugins;
1717

18+
import java.util.*;
1819
import java.util.concurrent.atomic.AtomicReference;
1920

2021
/**
@@ -26,7 +27,22 @@
2627
* property names)</li>
2728
* <li>default implementation</li>
2829
* </ol>
29-
*
30+
* <p>In addition to the {@code rxjava.plugin.[simple classname].implementation} system properties,
31+
* you can define two system property:<br>
32+
* <pre><code>
33+
* rxjava.plugin.[index].class}
34+
* rxjava.plugin.[index].impl}
35+
* </code></pre>
36+
*
37+
* Where the {@code .class} property contains the simple classname from above and the {@code .impl}
38+
* contains the fully qualified name of the implementation class. The {@code [index]} can be
39+
* any short string or number of your chosing. For example, you can now define a custom
40+
* {@code RxJavaErrorHandler} via two system property:
41+
* <pre><code>
42+
* rxjava.plugin.1.class=RxJavaErrorHandler
43+
* rxjava.plugin.1.impl=some.package.MyRxJavaErrorHandler
44+
* </code></pre>
45+
*
3046
* @see <a href="https://github.com/ReactiveX/RxJava/wiki/Plugins">RxJava Uncyclo: Plugins</a>
3147
*/
3248
public class RxJavaPlugins {
@@ -64,13 +80,12 @@ public static RxJavaPlugins getInstance() {
6480
* <p>
6581
* Override the default by calling {@link #registerErrorHandler(RxJavaErrorHandler)} or by setting the
6682
* property {@code rxjava.plugin.RxJavaErrorHandler.implementation} with the full classname to load.
67-
*
6883
* @return {@link RxJavaErrorHandler} implementation to use
6984
*/
7085
public RxJavaErrorHandler getErrorHandler() {
7186
if (errorHandler.get() == null) {
7287
// check for an implementation from System.getProperty first
73-
Object impl = getPluginImplementationViaProperty(RxJavaErrorHandler.class);
88+
Object impl = getPluginImplementationViaProperty(RxJavaErrorHandler.class, System.getProperties());
7489
if (impl == null) {
7590
// nothing set via properties so initialize with default
7691
errorHandler.compareAndSet(null, DEFAULT_ERROR_HANDLER);
@@ -112,7 +127,7 @@ public void registerErrorHandler(RxJavaErrorHandler impl) {
112127
public RxJavaObservableExecutionHook getObservableExecutionHook() {
113128
if (observableExecutionHook.get() == null) {
114129
// check for an implementation from System.getProperty first
115-
Object impl = getPluginImplementationViaProperty(RxJavaObservableExecutionHook.class);
130+
Object impl = getPluginImplementationViaProperty(RxJavaObservableExecutionHook.class, System.getProperties());
116131
if (impl == null) {
117132
// nothing set via properties so initialize with default
118133
observableExecutionHook.compareAndSet(null, RxJavaObservableExecutionHookDefault.getInstance());
@@ -141,15 +156,42 @@ public void registerObservableExecutionHook(RxJavaObservableExecutionHook impl)
141156
}
142157
}
143158

144-
private static Object getPluginImplementationViaProperty(Class<?> pluginClass) {
145-
String classSimpleName = pluginClass.getSimpleName();
159+
/* test */ static Object getPluginImplementationViaProperty(Class<?> pluginClass, Properties props) {
160+
final String classSimpleName = pluginClass.getSimpleName();
146161
/*
147162
* Check system properties for plugin class.
148163
* <p>
149164
* This will only happen during system startup thus it's okay to use the synchronized
150165
* System.getProperties as it will never get called in normal operations.
151166
*/
152-
String implementingClass = System.getProperty("rxjava.plugin." + classSimpleName + ".implementation");
167+
168+
final String pluginPrefix = "rxjava.plugin.";
169+
170+
String defaultKey = pluginPrefix + classSimpleName + ".implementation";
171+
String implementingClass = props.getProperty(defaultKey);
172+
173+
if (implementingClass == null) {
174+
final String classSuffix = ".class";
175+
final String implSuffix = ".impl";
176+
177+
for (Map.Entry<Object, Object> e : props.entrySet()) {
178+
String key = e.getKey().toString();
179+
if (key.startsWith(pluginPrefix) && key.endsWith(classSuffix)) {
180+
String value = e.getValue().toString();
181+
182+
if (classSimpleName.equals(value)) {
183+
String index = key.substring(0, key.length() - classSuffix.length()).substring(pluginPrefix.length());
184+
185+
String implKey = pluginPrefix + index + implSuffix;
186+
187+
implementingClass = props.getProperty(implKey);
188+
189+
break;
190+
}
191+
}
192+
}
193+
}
194+
153195
if (implementingClass != null) {
154196
try {
155197
Class<?> cls = Class.forName(implementingClass);
@@ -165,9 +207,9 @@ private static Object getPluginImplementationViaProperty(Class<?> pluginClass) {
165207
} catch (IllegalAccessException e) {
166208
throw new RuntimeException(classSimpleName + " implementation not able to be accessed: " + implementingClass, e);
167209
}
168-
} else {
169-
return null;
170210
}
211+
212+
return null;
171213
}
172214

173215
/**
@@ -183,7 +225,7 @@ private static Object getPluginImplementationViaProperty(Class<?> pluginClass) {
183225
public RxJavaSchedulersHook getSchedulersHook() {
184226
if (schedulersHook.get() == null) {
185227
// check for an implementation from System.getProperty first
186-
Object impl = getPluginImplementationViaProperty(RxJavaSchedulersHook.class);
228+
Object impl = getPluginImplementationViaProperty(RxJavaSchedulersHook.class, System.getProperties());
187229
if (impl == null) {
188230
// nothing set via properties so initialize with default
189231
schedulersHook.compareAndSet(null, RxJavaSchedulersHook.getDefaultInstance());

src/test/java/rx/plugins/RxJavaPluginsTest.java

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,12 @@
1515
*/
1616
package rx.plugins;
1717

18-
import static org.junit.Assert.assertEquals;
19-
import static org.junit.Assert.assertNotNull;
20-
import static org.junit.Assert.assertNull;
21-
import static org.junit.Assert.assertSame;
22-
import static org.junit.Assert.assertTrue;
23-
import static org.junit.Assert.fail;
24-
25-
import java.util.Calendar;
26-
import java.util.Collections;
27-
import java.util.Date;
18+
import static org.junit.Assert.*;
19+
20+
import java.util.*;
2821
import java.util.concurrent.TimeUnit;
2922

30-
import org.junit.After;
31-
import org.junit.Before;
32-
import org.junit.Test;
23+
import org.junit.*;
3324

3425
import rx.Observable;
3526
import rx.Subscriber;
@@ -251,4 +242,24 @@ private static String getFullClassNameForTestClass(Class<?> cls) {
251242
return RxJavaPlugins.class.getPackage()
252243
.getName() + "." + RxJavaPluginsTest.class.getSimpleName() + "$" + cls.getSimpleName();
253244
}
245+
246+
@Test
247+
public void testShortPluginDiscovery() {
248+
Properties props = new Properties();
249+
250+
props.setProperty("rxjava.plugin.1.class", "Map");
251+
props.setProperty("rxjava.plugin.1.impl", "java.util.HashMap");
252+
253+
props.setProperty("rxjava.plugin.xyz.class", "List");
254+
props.setProperty("rxjava.plugin.xyz.impl", "java.util.ArrayList");
255+
256+
257+
Object o = RxJavaPlugins.getPluginImplementationViaProperty(Map.class, props);
258+
259+
assertTrue("" + o, o instanceof HashMap);
260+
261+
o = RxJavaPlugins.getPluginImplementationViaProperty(List.class, props);
262+
263+
assertTrue("" + o, o instanceof ArrayList);
264+
}
254265
}

0 commit comments

Comments
 (0)