package ameba.core; import com.google.common.collect.Maps; import jersey.repackaged.com.google.common.collect.Collections2; import jersey.repackaged.com.google.common.collect.Lists; import jersey.repackaged.com.google.common.collect.Sets; import org.glassfish.hk2.api.ActiveDescriptor; import org.glassfish.hk2.api.ServiceHandle; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.jersey.message.MessageBodyWorkers; import org.glassfish.jersey.model.internal.RankedComparator; import org.glassfish.jersey.model.internal.RankedProvider; import org.glassfish.jersey.server.mvc.Viewable; import org.jvnet.hk2.annotations.Contract; import javax.ws.rs.ext.MessageBodyWriter; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.*; import java.util.stream.Collectors; /** * <p>ServiceLocators class.</p> * * @author icode * @since 0.1.6e * */ @SuppressWarnings("ALL") public class ServiceLocators { private ServiceLocators() { } /** * <p>getViewableMessageBodyWriter.</p> * * @param workers a {@link org.glassfish.jersey.message.MessageBodyWorkers} object. * @return a {@link javax.ws.rs.ext.MessageBodyWriter} object. */ public static MessageBodyWriter<Viewable> getViewableMessageBodyWriter(MessageBodyWorkers workers) { return workers.getMessageBodyWriter(Viewable.class, null, new Annotation[]{}, null); } /** * <p>getServiceHandles.</p> * * @param locator a {@link org.glassfish.hk2.api.ServiceLocator} object. * @param contract a {@link java.lang.Class} object. * @param qualifiers a {@link java.lang.annotation.Annotation} object. * @param <T> a T object. * @return a {@link java.util.List} object. */ public static <T> List<ServiceHandle<T>> getServiceHandles(final ServiceLocator locator, final Class<T> contract, final Annotation... qualifiers) { final List<ServiceHandle<T>> allServiceHandles = qualifiers == null ? locator.getAllServiceHandles(contract) : locator.getAllServiceHandles(contract, qualifiers); //noinspection unchecked return allServiceHandles.stream().map(handle -> handle).collect(Collectors.toCollection(ArrayList::new)); } /** * Get the iterable of {@link RankedProvider providers} (default) registered for the given service provider * contract in the underlying {@link ServiceLocator HK2 service locator} container. * * @param <T> service provider contract Java type. * @param locator underlying HK2 service locator. * @param contract service provider contract. * @return iterable of all available ranked service providers for the contract. Return value is never null. */ public static <T> Iterable<RankedProvider<T>> getRankedProviders(final ServiceLocator locator, final Class<T> contract) { final List<ServiceHandle<T>> providers = getServiceHandles(locator, contract); final Map<ActiveDescriptor<T>, RankedProvider<T>> providerMap = Maps.newLinkedHashMap(); for (final ServiceHandle<T> provider : providers) { final ActiveDescriptor<T> key = provider.getActiveDescriptor(); if (!providerMap.containsKey(key)) { final Set<Type> contractTypes = key.getContractTypes(); final Class<?> implementationClass = key.getImplementationClass(); boolean proxyGenerated = true; for (Type ct : contractTypes) { if (((Class<?>) ct).isAssignableFrom(implementationClass)) { proxyGenerated = false; break; } } providerMap.put(key, new RankedProvider<>(provider.getService(), key.getRanking(), proxyGenerated ? contractTypes : null)); } } return providerMap.values(); } /** * Sort given providers with {@link RankedComparator ranked comparator}. * * @param comparator comparator to sort the providers with. * @param providers providers to be sorted. * @param <T> service provider contract Java type. * @return sorted {@link Iterable iterable} instance containing given providers. * The returned value is never {@code null}. */ @SuppressWarnings("TypeMayBeWeakened") public static <T> Iterable<T> sortRankedProviders(final RankedComparator<T> comparator, final Iterable<RankedProvider<T>> providers) { final List<RankedProvider<T>> rankedProviders = Lists.newArrayList(providers); Collections.sort(rankedProviders, comparator); return Collections2.transform(rankedProviders, RankedProvider::getProvider); } public static Set<Class<?>> getProviderContracts(final Class<?> clazz) { final Set<Class<?>> contracts = Sets.newIdentityHashSet(); computeProviderContracts(clazz, contracts); return contracts; } private static void computeProviderContracts(final Class<?> clazz, final Set<Class<?>> contracts) { for (final Class<?> contract : getImplementedContracts(clazz)) { if (isSupportedContract(contract)) { contracts.add(contract); } computeProviderContracts(contract, contracts); } } private static Iterable<Class<?>> getImplementedContracts(final Class<?> clazz) { final Collection<Class<?>> list = new LinkedList<>(); Collections.addAll(list, clazz.getInterfaces()); final Class<?> superclass = clazz.getSuperclass(); if (superclass != null) { list.add(superclass); } return list; } public static boolean isSupportedContract(final Class<?> type) { return type.isAnnotationPresent(Contract.class) || type.isAnnotationPresent(org.glassfish.jersey.spi.Contract.class); } }