Skip to content

Commit

Permalink
Fix #118. Use ServiceLoader to load services
Browse files Browse the repository at this point in the history
FactoryFinder is very, possibly overly, generic. It looks like it was
written to re-use across multiple projects. I was tempted by a larger
refactoring as well as a greater use of generics but I opted to just fix
the immediate issue. Wider refactorings can follow later if there is
interest in that.
  • Loading branch information
markt-asf committed Jan 27, 2020
1 parent 32b3052 commit 6075bc9
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 26 deletions.
3 changes: 2 additions & 1 deletion api/src/main/java/jakarta/el/ExpressionFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ public static ExpressionFactory newInstance() {
* @return a new <code>ExpressionFactory</code> instance
*/
public static ExpressionFactory newInstance(Properties properties) {
return (ExpressionFactory) FactoryFinder.find("jakarta.el.ExpressionFactory", "com.sun.el.ExpressionFactoryImpl", properties);
return (ExpressionFactory) FactoryFinder.find(ExpressionFactory.class,
"jakarta.el.ExpressionFactory", "com.sun.el.ExpressionFactoryImpl", properties);
}

/**
Expand Down
42 changes: 17 additions & 25 deletions api/src/main/java/jakarta/el/FactoryFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@

import static java.io.File.separator;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.util.Iterator;
import java.util.Properties;
import java.util.ServiceLoader;

class FactoryFinder {

Expand Down Expand Up @@ -64,46 +63,39 @@ private static Object newInstance(String className, ClassLoader classLoader, Pro
}

/**
* Finds the implementation <code>Class</code> object for the given factory name, or if that fails, finds the
* <code>Class</code> object for the given fallback class name. The arguments supplied must be used in order. If using
* the first argument is successful, the second one will not be used.
* <P>
* Finds the implementation <code>Class</code> object for the given factory. The following search order is used:
* <ol>
* <li>{@link ServiceLoader} lookup using <code>serviceClass</code></li>
* <li>Property file located as <code>$java.home/lib/el.properties</code></li>
* <li>System property lookup using <code>factoryId</code></li>
* <li>Create an instance of <code>fallbackClassName</code></li>
* </ol>
* This method is package private so that this code can be shared.
*
* @return the <code>Class</code> object of the specified message factory; may not be <code>null</code>
*
* @param serviceClass The class to use when searching for the factory using the ServiceLoader mechanism
* @param factoryId the name of the factory to find, which is a system property
* @param fallbackClassName the implementation class name, which is to be used only if nothing else is found;
* <code>null</code> to indicate that there is no fallback class name
* @exception ELException if there is an error
*/
static Object find(String factoryId, String fallbackClassName, Properties properties) {
static Object find(Class<?> serviceClass, String factoryId, String fallbackClassName, Properties properties) {
ClassLoader classLoader;
try {
classLoader = Thread.currentThread().getContextClassLoader();
} catch (Exception x) {
throw new ELException(x.toString(), x);
}

String serviceId = "META-INF/services/" + factoryId;

// try to find services in CLASSPATH
try {
InputStream is = null;
if (classLoader == null) {
is = ClassLoader.getSystemResourceAsStream(serviceId);
} else {
is = classLoader.getResourceAsStream(serviceId);
}

if (is != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));

String factoryClassName = reader.readLine();
reader.close();

if (factoryClassName != null && !"".equals(factoryClassName)) {
return newInstance(factoryClassName, classLoader, properties);
ServiceLoader<?> serviceLoader = ServiceLoader.load(serviceClass, classLoader);
Iterator<?> iter = serviceLoader.iterator();
while (iter.hasNext()) {
Object service = iter.next();
if (service != null) {
return service;
}
}
} catch (Exception ex) {
Expand Down

0 comments on commit 6075bc9

Please sign in to comment.