All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.arquillian.container.test.impl.RemoteExtensionLoader Maven / Gradle / Ivy

There is a newer version: 1.9.1.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2009 Red Hat Inc. and/or its affiliates and other contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * 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 org.jboss.arquillian.container.test.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import org.jboss.arquillian.container.test.spi.RemoteLoadableExtension;
import org.jboss.arquillian.core.spi.ExtensionLoader;
import org.jboss.arquillian.core.spi.LoadableExtension;
import org.jboss.arquillian.core.spi.Validate;

/**
 * ARQ-456 Temp fix. Load a different type of LoadableExtension on the container side, RemoteLoadableExtension.
 * 

* Should be replaced when proper Modularity, Classloading is in order. *

* ServiceLoader implementation that use META-INF/services/interface files to registered Services. * * @author Aslak Knutsen * @version $Revision: $ */ public class RemoteExtensionLoader implements ExtensionLoader { //-------------------------------------------------------------------------------------|| // Class Members ----------------------------------------------------------------------|| //-------------------------------------------------------------------------------------|| private static final String SERVICES = "META-INF/services"; private static final String EXCLUSIONS = "META-INF/exclusions"; //-------------------------------------------------------------------------------------|| // Required Implementations - ExtensionLoader -----------------------------------------|| //-------------------------------------------------------------------------------------|| @Override public Collection load() { List extensions = new ArrayList(); Collection loaded = Collections.emptyList(); if (SecurityActions.getThreadContextClassLoader() != null) { loaded = all(SecurityActions.getThreadContextClassLoader(), RemoteLoadableExtension.class); } if (loaded.size() == 0) { loaded = all(RemoteExtensionLoader.class.getClassLoader(), RemoteLoadableExtension.class); } for (RemoteLoadableExtension extension : loaded) { extensions.add(extension); } return extensions; } @Override public Map, Set>> loadVetoed() { return loadVetoed(SecurityActions.getThreadContextClassLoader()); } //-------------------------------------------------------------------------------------|| // General JDK SPI Loader -------------------------------------------------------------|| //-------------------------------------------------------------------------------------|| private Collection all(ClassLoader classLoader, Class serviceClass) { Validate.notNull(classLoader, "ClassLoader must be provided"); Validate.notNull(serviceClass, "ServiceClass must be provided"); return createInstances( serviceClass, load(serviceClass, classLoader)); } /** * This method first finds all files that are in claspath placed at META-INF/exclusions * Each of this file has a name that represents the service type that needs to veto. * The content of this file is a list of real implementations that you want to veto. * * @return List of vetos */ public Map, Set>> loadVetoed(ClassLoader classLoader) { Validate.notNull(classLoader, "ClassLoader must be provided"); final Map, Set>> vetoed = new LinkedHashMap, Set>>(); try { final Enumeration exclusions = classLoader.getResources(EXCLUSIONS); while (exclusions.hasMoreElements()) { URL exclusion = exclusions.nextElement(); Properties vetoedElements = new Properties(); final InputStream inStream = exclusion.openStream(); try { vetoedElements.load(inStream); final Set> entries = vetoedElements.entrySet(); for (Map.Entry entry : entries) { String service = (String) entry.getKey(); String serviceImpls = (String) entry.getValue(); addVetoedClasses(service, serviceImpls, classLoader, vetoed); } } finally { if (inStream != null) { inStream.close(); } } } } catch (IOException e) { throw new RuntimeException("Could not load exclusions from " + EXCLUSIONS, e); } return vetoed; } //-------------------------------------------------------------------------------------|| // Internal Helper Methods - Service Loading ------------------------------------------|| //-------------------------------------------------------------------------------------|| private void addVetoedClasses(String serviceName, String serviceImpls, ClassLoader classLoader, Map, Set>> vetoed) { try { final Class serviceClass = classLoader.loadClass(serviceName); final Set> classes = loadVetoedServiceImpl(serviceImpls, classLoader); final Set> registeredVetoedClasses = vetoed.get(serviceClass); if (registeredVetoedClasses == null) { vetoed.put(serviceClass, classes); } else { registeredVetoedClasses.addAll(classes); } } catch (ClassNotFoundException e) { // ignores since this is a veto that it is not applicable } } private Set> loadVetoedServiceImpl(String serviceImpls, ClassLoader classLoader) { final StringTokenizer serviceImplsSeparator = new StringTokenizer(serviceImpls, ","); final Set> serviceImplsClass = new LinkedHashSet>(); while (serviceImplsSeparator.hasMoreTokens()) { try { serviceImplsClass.add(classLoader.loadClass(serviceImplsSeparator.nextToken().trim())); } catch (ClassNotFoundException e) { // ignores since this is a veto that it is not applicable } } return serviceImplsClass; } private Set> load(Class serviceClass, ClassLoader loader) { String serviceFile = SERVICES + "/" + serviceClass.getName(); LinkedHashSet> providers = new LinkedHashSet>(); LinkedHashSet> vetoedProviders = new LinkedHashSet>(); try { Enumeration enumeration = loader.getResources(serviceFile); while (enumeration.hasMoreElements()) { final URL url = enumeration.nextElement(); final InputStream is = url.openStream(); BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); String line = reader.readLine(); while (null != line) { line = skipCommentAndTrim(line); if (line.length() > 0) { try { boolean mustBeVetoed = line.startsWith("!"); if (mustBeVetoed) { line = line.substring(1); } Class provider = loader.loadClass(line).asSubclass(serviceClass); if (mustBeVetoed) { vetoedProviders.add(provider); } if (vetoedProviders.contains(provider)) { providers.remove(provider); } else { providers.add(provider); } } catch (ClassCastException e) { throw new IllegalStateException("Service " + line + " does not implement expected type " + serviceClass.getName()); } } line = reader.readLine(); } } finally { if (reader != null) { reader.close(); } } } } catch (Exception e) { throw new RuntimeException("Could not load services for " + serviceClass.getName(), e); } return providers; } private String skipCommentAndTrim(String line) { final int comment = line.indexOf('#'); if (comment > -1) { line = line.substring(0, comment); } line = line.trim(); return line; } private Set createInstances(Class serviceType, Set> providers) { Set providerImpls = new LinkedHashSet(); for (Class serviceClass : providers) { providerImpls.add(createInstance(serviceClass)); } return providerImpls; } /** * Create a new instance of the found Service.
*

* Verifies that the found ServiceImpl implements Service. * * @param serviceType * The Service interface * @param className * The name of the implementation class * @param loader * The ClassLoader to load the ServiceImpl from * * @return A new instance of the ServiceImpl * * @throws Exception * If problems creating a new instance */ private T createInstance(Class serviceImplClass) { try { return SecurityActions.newInstance(serviceImplClass, new Class[0], new Object[0]); } catch (Exception e) { throw new RuntimeException( "Could not create a new instance of Service implementation " + serviceImplClass.getName(), e); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy