Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.util;
import com.hazelcast.core.HazelcastException;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.nio.ClassLoaderUtil;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import static com.hazelcast.nio.IOUtil.closeResource;
import static com.hazelcast.util.EmptyStatement.ignore;
import static com.hazelcast.util.Preconditions.isNotNull;
import static java.lang.Boolean.getBoolean;
/**
* Support class for loading Hazelcast services and hooks based on the Java {@link ServiceLoader} specification,
* but changed in the fact of classloaders to test for given services to work in multi classloader
* environments like application or OSGi servers.
*/
public final class ServiceLoader {
//compatibility flag to re-introduce behaviour from 3.8.0 with classloading fallbacks
private static final boolean USE_CLASSLOADING_FALLBACK = getBoolean("hazelcast.compat.classloading.hooks.fallback");
private static final ILogger LOGGER = Logger.getLogger(ServiceLoader.class);
private static final String FILTERING_CLASS_LOADER = FilteringClassLoader.class.getCanonicalName();
// see https://github.com/hazelcast/hazelcast/issues/3922
private static final String IGNORED_GLASSFISH_MAGIC_CLASSLOADER =
"com.sun.enterprise.v3.server.APIClassLoaderServiceImpl$APIClassLoader";
private ServiceLoader() {
}
public static T load(Class clazz, String factoryId, ClassLoader classLoader) throws Exception {
Iterator iterator = iterator(clazz, factoryId, classLoader);
if (iterator.hasNext()) {
return iterator.next();
}
return null;
}
public static Iterator iterator(Class expectedType, String factoryId, ClassLoader classLoader) throws Exception {
Set serviceDefinitions = getServiceDefinitions(factoryId, classLoader);
ClassIterator classIterator = new ClassIterator(serviceDefinitions, expectedType);
return new NewInstanceIterator(classIterator);
}
public static Iterator> classIterator(Class expectedType, String factoryId, ClassLoader classLoader)
throws Exception {
Set serviceDefinitions = getServiceDefinitions(factoryId, classLoader);
return new ClassIterator(serviceDefinitions, expectedType);
}
private static Set getServiceDefinitions(String factoryId, ClassLoader classLoader) {
List classLoaders = selectClassLoaders(classLoader);
Set factoryUrls = new HashSet();
for (ClassLoader selectedClassLoader : classLoaders) {
factoryUrls.addAll(collectFactoryUrls(factoryId, selectedClassLoader));
}
Set serviceDefinitions = new HashSet();
for (URLDefinition urlDefinition : factoryUrls) {
serviceDefinitions.addAll(parse(urlDefinition));
}
if (serviceDefinitions.isEmpty()) {
Logger.getLogger(ServiceLoader.class).finest(
"Service loader could not load 'META-INF/services/" + factoryId + "' It may be empty or does not exist.");
}
return serviceDefinitions;
}
private static Set collectFactoryUrls(String factoryId, ClassLoader classLoader) {
String resourceName = "META-INF/services/" + factoryId;
try {
Enumeration configs;
if (classLoader != null) {
configs = classLoader.getResources(resourceName);
} else {
configs = ClassLoader.getSystemResources(resourceName);
}
Set urlDefinitions = new HashSet();
while (configs.hasMoreElements()) {
URL url = configs.nextElement();
URI uri = new URI(url.toExternalForm().replace(" ", "%20"));
ClassLoader highestClassLoader = findHighestReachableClassLoader(url, classLoader, resourceName);
if (!highestClassLoader.getClass().getName().equals(IGNORED_GLASSFISH_MAGIC_CLASSLOADER)) {
urlDefinitions.add(new URLDefinition(uri, highestClassLoader));
}
}
return urlDefinitions;
} catch (Exception e) {
LOGGER.severe(e);
}
return Collections.emptySet();
}
private static Set parse(URLDefinition urlDefinition) {
try {
Set names = new HashSet();
BufferedReader r = null;
try {
URL url = urlDefinition.uri.toURL();
r = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
while (true) {
String line = r.readLine();
if (line == null) {
break;
}
int comment = line.indexOf('#');
if (comment >= 0) {
line = line.substring(0, comment);
}
String name = line.trim();
if (name.length() == 0) {
continue;
}
names.add(new ServiceDefinition(name, urlDefinition.classLoader));
}
} finally {
closeResource(r);
}
return names;
} catch (Exception e) {
LOGGER.severe(e);
}
return Collections.emptySet();
}
private static ClassLoader findHighestReachableClassLoader(URL url, ClassLoader classLoader, String resourceName) {
if (classLoader.getParent() == null) {
return classLoader;
}
ClassLoader highestClassLoader = classLoader;
ClassLoader current = classLoader;
while (current.getParent() != null) {
// if we have a filtering classloader in hierarchy, we need to stop!
if (FILTERING_CLASS_LOADER.equals(current.getClass().getCanonicalName())) {
break;
}
ClassLoader parent = current.getParent();
try {
Enumeration resources = parent.getResources(resourceName);
if (resources != null) {
while (resources.hasMoreElements()) {
URL resourceURL = resources.nextElement();
if (url.toURI().equals(resourceURL.toURI())) {
highestClassLoader = parent;
}
}
}
} catch (IOException ignore) {
// we want to ignore failures and keep searching
ignore(ignore);
} catch (URISyntaxException ignore) {
// we want to ignore failures and keep searching
ignore(ignore);
}
// going on with the search upwards the hierarchy
current = current.getParent();
}
return highestClassLoader;
}
static List selectClassLoaders(ClassLoader classLoader) {
// list prevents reordering!
List classLoaders = new ArrayList();
if (classLoader != null) {
classLoaders.add(classLoader);
}
// check if TCCL is same as given classLoader
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
if (tccl != classLoader) {
classLoaders.add(tccl);
}
// Hazelcast core classLoader
ClassLoader coreClassLoader = ServiceLoader.class.getClassLoader();
if (coreClassLoader != classLoader && coreClassLoader != tccl) {
classLoaders.add(coreClassLoader);
}
// Hazelcast client classLoader
try {
Class> hzClientClass = Class.forName("com.hazelcast.client.HazelcastClient");
ClassLoader clientClassLoader = hzClientClass.getClassLoader();
if (clientClassLoader != classLoader && clientClassLoader != tccl && clientClassLoader != coreClassLoader) {
classLoaders.add(clientClassLoader);
}
} catch (ClassNotFoundException ignore) {
// ignore since we does not have HazelcastClient in classpath
ignore(ignore);
}
return classLoaders;
}
/**
* Definition of the internal service based on classloader that is able to load it
* and the classname of the found service.
*/
static final class ServiceDefinition {
private final String className;
private final ClassLoader classLoader;
public ServiceDefinition(String className, ClassLoader classLoader) {
this.className = isNotNull(className, "className");
this.classLoader = isNotNull(classLoader, "classLoader");
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ServiceDefinition that = (ServiceDefinition) o;
if (!classLoader.equals(that.classLoader)) {
return false;
}
if (!className.equals(that.className)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = className.hashCode();
result = 31 * result + classLoader.hashCode();
return result;
}
}
/**
* This class keeps track of available service definition URLs and
* the corresponding classloaders.
*/
private static final class URLDefinition {
private final URI uri;
private final ClassLoader classLoader;
private URLDefinition(URI url, ClassLoader classLoader) {
this.uri = url;
this.classLoader = classLoader;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
URLDefinition that = (URLDefinition) o;
if (uri != null ? !uri.equals(that.uri) : that.uri != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
return uri == null ? 0 : uri.hashCode();
}
}
static class NewInstanceIterator implements Iterator {
private final Iterator> classIterator;
NewInstanceIterator(Iterator> classIterator) {
this.classIterator = classIterator;
}
@Override
public boolean hasNext() {
return classIterator.hasNext();
}
@Override
public T next() {
Class clazz = classIterator.next();
try {
Constructor constructor = clazz.getDeclaredConstructor();
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance();
} catch (InstantiationException e) {
throw new HazelcastException(e);
} catch (IllegalAccessException e) {
throw new HazelcastException(e);
} catch (NoSuchMethodException e) {
throw new HazelcastException(e);
} catch (InvocationTargetException e) {
throw new HazelcastException(e);
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* Iterates over services. It skips services which implement an interface with the expected name,
* but loaded by a different classloader.
*
* When a service does not implement an interface with expected name then it throws an exception
*
* @param
*/
static class ClassIterator implements Iterator> {
private final Iterator iterator;
private final Class expectedType;
private Class nextClass;
ClassIterator(Set serviceDefinitions, Class expectedType) {
iterator = serviceDefinitions.iterator();
this.expectedType = expectedType;
}
@Override
public boolean hasNext() {
if (nextClass != null) {
return true;
}
return advance();
}
private boolean advance() {
while (iterator.hasNext()) {
ServiceDefinition definition = iterator.next();
String className = definition.className;
ClassLoader classLoader = definition.classLoader;
try {
Class> candidate = loadClass(className, classLoader);
if (expectedType.isAssignableFrom(candidate)) {
nextClass = (Class) candidate;
return true;
} else {
onNonAssignableClass(className, candidate);
}
} catch (ClassNotFoundException e) {
onClassNotFoundException(className, classLoader, e);
}
}
return false;
}
private Class> loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException {
Class> candidate;
if (USE_CLASSLOADING_FALLBACK) {
candidate = ClassLoaderUtil.loadClass(classLoader, className);
} else {
candidate = classLoader.loadClass(className);
}
return candidate;
}
private void onClassNotFoundException(String className, ClassLoader classLoader, ClassNotFoundException e) {
if (className.startsWith("com.hazelcast")) {
LOGGER.fine("Failed to load " + className + " by " + classLoader
+ ". This indicates a classloading issue. It can happen in a runtime with "
+ "a complicated classloading model. (OSGi, Java EE, etc);");
} else {
throw new HazelcastException(e);
}
}
private void onNonAssignableClass(String className, Class candidate) {
if (expectedType.isInterface()) {
if (ClassLoaderUtil.implementsInterfaceWithSameName(candidate, expectedType)) {
// this can happen in application containers - different Hazelcast JARs are loaded
// by different classloaders.
LOGGER.fine("There appears to be a classloading conflict. "
+ "Class " + className + " loaded by " + candidate.getClassLoader() + " does not "
+ "implement " + expectedType.getClass().getName() + " loaded by "
+ expectedType.getClass().getClassLoader());
} else {
// ok, the class does not implement interface with the expected name. it's probably
// an error in hook implementation -> let's fail fast
throw new ClassCastException("Class " + className + " does not implement "
+ expectedType.getName());
}
}
}
@Override
@SuppressWarnings("unchecked")
public Class next() {
if (nextClass == null) {
advance();
}
if (nextClass == null) {
throw new NoSuchElementException();
}
Class classToReturn = nextClass;
nextClass = null;
return classToReturn;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}