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 2013 Red Hat Inc. and/or its affiliates and other 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.switchyard.test;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.custommonkey.xmlunit.XMLAssert;
import org.custommonkey.xmlunit.XMLUnit;
import org.jboss.logging.Logger;
import org.junit.Assert;
import org.switchyard.ExchangeHandler;
import org.switchyard.Service;
import org.switchyard.ServiceDomain;
import org.switchyard.SwitchYardException;
import org.switchyard.common.type.Classes;
import org.switchyard.common.type.classpath.ClasspathScanner;
import org.switchyard.common.xml.XMLHelper;
import org.switchyard.config.model.MergeScanner;
import org.switchyard.config.model.Model;
import org.switchyard.config.model.ModelPuller;
import org.switchyard.config.model.Models;
import org.switchyard.config.model.Scannable;
import org.switchyard.config.model.Scanner;
import org.switchyard.config.model.ScannerInput;
import org.switchyard.config.model.ScannerOutput;
import org.switchyard.config.model.composite.CompositeModel;
import org.switchyard.config.model.switchyard.SwitchYardModel;
import org.switchyard.config.model.switchyard.SwitchYardNamespace;
import org.switchyard.config.model.switchyard.v1.V1SwitchYardModel;
import org.switchyard.config.model.transform.TransformModel;
import org.switchyard.deploy.Activator;
import org.switchyard.deploy.ActivatorLoader;
import org.switchyard.deploy.ServiceDomainManager;
import org.switchyard.deploy.internal.AbstractDeployment;
import org.switchyard.deploy.internal.Deployment;
import org.switchyard.handlers.MessageTraceHandler;
import org.switchyard.metadata.InOnlyService;
import org.switchyard.metadata.InOutService;
import org.switchyard.metadata.ServiceInterface;
import org.switchyard.test.mixins.AbstractTestMixIn;
import org.switchyard.transform.BaseTransformer;
import org.switchyard.transform.Transformer;
import org.w3c.dom.Document;
/**
* @author [email protected]
*/
public class SwitchYardTestKit {
/**
* Logger.
*/
private static Logger _logger = Logger.getLogger(SwitchYardTestKit.class);
/**
* Constant for the {@link org.switchyard.test.SwitchYardTestCaseConfig#config()} default.
*/
protected static final String NULL_CONFIG = "$$NULL_SW_CONFIG$$";
/**
* Class test instance.
*/
private Object _testInstance;
/**
* Test configuration model.
*/
private SwitchYardModel _configModel;
/**
* The deployment.
*/
private AbstractDeployment _deployment;
/**
* Test Mix-Ins.
*/
private Map, MixInEntry> _testMixInInstances =
new LinkedHashMap, MixInEntry>();
private List _activators;
/**
* Public default constructor.
* @param testInstance The test instance.
* @exception Exception Error initializing test kit.
*/
public SwitchYardTestKit(Object testInstance) throws Exception {
this._testInstance = testInstance;
SwitchYardTestCaseConfig testCaseConfig = testInstance.getClass().getAnnotation(SwitchYardTestCaseConfig.class);
if (testCaseConfig != null) {
String config = testCaseConfig.config();
if (config != null && !config.equals(NULL_CONFIG)) {
InputStream is = getResourceAsStream(config);
if (is == null) {
// Try the file system...
File file = new File(config);
if (file.isFile()) {
is = new FileInputStream(file);
}
}
if (is == null) {
Assert.fail("Failed to locate test configuration '" + config + "' on the classpath or project sub-directory. See the @" + SwitchYardTestCaseConfig.class.getSimpleName() + " annotation on test class '" + _testInstance.getClass().getName() + "'.");
}
try {
_configModel = createSwitchYardModel(is, createScanners(testCaseConfig), testCaseConfig.validate());
} finally {
try {
is.close();
} catch (Throwable t) {
// just to keep checkstyle happy
t.getMessage();
}
}
}
Class extends TestMixIn>[] testMixIns = testCaseConfig.mixins();
if (testMixIns == null) {
// No MixIns...
_logger.debug("No TestMixIns for test.");
} else if (testMixIns.length == 1 && testMixIns[0] == NullMixIns.class) {
// No MixIns...
_logger.debug("No TestMixIns for test.");
} else {
for (Class extends TestMixIn> mixIn : testMixIns) {
_testMixInInstances.put(mixIn, null);
}
}
}
createMixInInstances();
initializeMixIns();
}
/**
* invoke the methods annotated with {@link BeforeDeploy} on test class and deploy SwitchYard application.
*
* @throws Exception failed to deploy
*/
public void start() throws Exception {
beforeDeploy();
deploy();
}
/**
* Cleanup.
*/
public void cleanup() {
undeploy();
cleanupMixIns();
}
/**
* Get the test class instance.
* @return The test class instance.
*/
public Object getTestInstance() {
return _testInstance;
}
/**
* Get the configuration model driving this test instance, if one exists.
*
* An abstract deployment is created if no configuration model is supplied on construction.
*
* @return The config model, or null if no config model was used to construct the TestCase instance.
*/
public SwitchYardModel getConfigModel() {
return _configModel;
}
/**
* Get the list of activators for the test.
* @return Activator list.
*/
public List getActivators() {
return _activators;
}
/**
* Get the deployment instance associated with the test case.
* @return The deployment instance associated with the test case.
*/
public AbstractDeployment getDeployment() {
return _deployment;
}
/**
* Get the ServiceDomain.
* @return The service domain.
*/
public ServiceDomain getServiceDomain() {
assertDeployed();
return _deployment.getDomain();
}
/**
* Creates a QName given this test kit's config model's targetNamespace + the specified localPart.
* @param localPart the specified localPart
* @return the QName
*/
public QName createQName(String localPart) {
final String tns;
if (_configModel != null) {
CompositeModel composite = _configModel.getComposite();
tns = composite != null ? composite.getTargetNamespace() : _configModel.getTargetNamespace();
} else {
tns = null;
}
return XMLHelper.createQName(tns, localPart);
}
/**
* Register an IN_OUT Service.
*
* Registers a {@link MockHandler} as the service handler.
*
* @param serviceName The Service name.
* @return The {@link MockHandler} service handler.
*/
public MockHandler registerInOutService(String serviceName) {
MockHandler handler = new MockHandler();
getServiceDomain().registerService(createQName(serviceName), new InOutService(), handler);
return handler;
}
/**
* Register an IN_OUT Service.
*
* @param serviceName The Service name.
* @param serviceHandler The service handler.
*/
public void registerInOutService(String serviceName, ExchangeHandler serviceHandler) {
getServiceDomain().registerService(createQName(serviceName), new InOutService(), serviceHandler);
}
/**
* Register an IN_OUT Service.
*
* @param serviceName The Service name.
* @param serviceHandler The service handler.
* @param metadata Service interface.
*/
public void registerInOutService(String serviceName, ExchangeHandler serviceHandler, ServiceInterface metadata) {
getServiceDomain().registerService(createQName(serviceName), metadata, serviceHandler);
}
/**
* Register an IN_ONLY Service.
*
* Registers a {@link MockHandler} as the fault service handler.
*
* @param serviceName The Service name.
* @return The {@link MockHandler} service fault handler.
*/
public MockHandler registerInOnlyService(String serviceName) {
MockHandler handler = new MockHandler();
getServiceDomain().registerService(createQName(serviceName), new InOnlyService(), handler);
return handler;
}
/**
* Register an IN_ONLY Service.
*
* @param serviceName The Service name.
* @param serviceHandler The service handler.
*/
public void registerInOnlyService(String serviceName, ExchangeHandler serviceHandler) {
getServiceDomain().registerService(createQName(serviceName), new InOnlyService(), serviceHandler);
}
/**
* Replaces an existing service registration (e.g. reference binding) with a test handler using
* the same contract as the existing service provider. If multiple services are registered with
* the specified name, the first one found is used. Generally speaking, it's not a good idea
* to use this method if you have multiple services registered with the same name. In that
* situation, use the removeService() and registerService() methods instead.
* @param name name of the service to replace
* @return mock service handler representing the service provider
* @throws SwitchYardException if a service with the specified name does not exist
*/
public MockHandler replaceService(String name) throws SwitchYardException {
return replaceService(createQName(name));
}
/**
* Replaces an existing service registration (e.g. reference binding) with a test handler using
* the same contract as the existing service provider. If multiple services are registered with
* the specified name, the first one found is used. Generally speaking, it's not a good idea
* to use this method if you have multiple services registered with the same name. In that
* situation, use the removeService() and registerService() methods instead.
* @param name name of the service to replace
* @param handler implementation to use as the service provider
* @throws SwitchYardException if a service with the specified name does not exist
*/
public void replaceService(String name, ExchangeHandler handler) throws SwitchYardException {
replaceService(createQName(name), handler);
}
/**
* Replaces an existing service registration (e.g. reference binding) with a test handler using
* the same contract as the existing service provider. If multiple services are registered with
* the specified name, the first one found is used. Generally speaking, it's not a good idea
* to use this method if you have multiple services registered with the same name. In that
* situation, use the removeService() and registerService() methods instead.
* @param name name of the service to replace
* @return mock service handler representing the service provider
* @throws SwitchYardException if a service with the specified name does not exist
*/
public MockHandler replaceService(QName name) throws SwitchYardException {
MockHandler handler = new MockHandler();
replaceService(name, handler);
return handler;
}
/**
* Replaces an existing service registration (e.g. reference binding) with a test handler using
* the same contract as the existing service provider. If multiple services are registered with
* the specified name, the first one found is used. Generally speaking, it's not a good idea
* to use this method if you have multiple services registered with the same name. In that
* situation, use the removeService() and registerService() methods instead.
* @param name name of the service to replace
* @param handler implementation to use as the service provider
* @throws SwitchYardException if a service with the specified name does not exist
*/
public void replaceService(QName name, ExchangeHandler handler) throws SwitchYardException {
List services = getServiceDomain().getServices(name);
if (services.isEmpty()) {
throw new SwitchYardException("Failed to replace service: " + name
+ ". No service is registered with that name.");
}
// select the service to replace
Service replacedService = services.get(0);
replacedService.unregister();
// add the replacement service
getServiceDomain().registerService(name, replacedService.getInterface(), handler,
replacedService.getServiceMetadata());
}
/**
* Removes all service providers from the domain with the specified name.
* @param serviceName local part of a service QName
*/
public void removeService(String serviceName) {
removeService(createQName(serviceName));
}
/**
* Removes all service providers from the domain with the specified name.
* @param serviceName qualified name of the service
*/
public void removeService(QName serviceName) {
for (Service service : getServiceDomain().getServices(serviceName)) {
service.unregister();
}
}
/**
* Add a Transformer instance.
* @param transformer The transformer instance.
*/
public void addTransformer(Transformer transformer) {
getServiceDomain().getTransformerRegistry().addTransformer(transformer);
}
/**
* Create a new {@link Invoker} instance for invoking a Service in the test ServiceDomain.
* @param serviceName The target Service name.
* @return The invoker instance.
*/
public Invoker newInvoker(QName serviceName) {
return new Invoker(getServiceDomain(), serviceName);
}
/**
* Create a new {@link Invoker} instance for invoking a Service in the test ServiceDomain.
* @param serviceName The target Service name. Can be a serialized {@link QName}. Can also
* include the operation name e.g. "OrderManagementService.createOrder".
* @return The invoker instance.
*/
public Invoker newInvoker(String serviceName) {
return newInvoker(createQName(serviceName));
}
/**
* Create a new {@link Transformer} instance from the specified {@link org.switchyard.config.model.transform.TransformModel}.
* @param transformModel The TransformModel.
* @return The Transformer instance.
*/
public Transformer newTransformer(TransformModel transformModel) {
return _deployment.getTransformerRegistryLoader().newTransformer(transformModel);
}
/**
* Create a new {@link Transformer} instance from the specified {@link TransformModel} and
* register it with the test ServiceDomain.
* @param transformModel The TransformModel.
* @return The Transformer instance.
*/
public Transformer registerTransformer(TransformModel transformModel) {
if (transformModel.getFrom() == null || transformModel.getTo() == null) {
Assert.fail("Invalid TransformModel instance. Must specify 'from' and 'to' data types.");
}
Transformer,?> transformer = _deployment.getTransformerRegistryLoader().newTransformer(transformModel);
if (transformer.getFrom() == null) {
transformer = new TransformerWrapper(transformer, transformModel);
}
_deployment.getDomain().getTransformerRegistry().addTransformer(transformer);
return transformer;
}
/**
* Get the {@link TestMixIn} instances associated with this test instance.
* @return The {@link TestMixIn} instances associated with this test instance.
*/
public List getMixIns() {
List mixins = new ArrayList();
for (MixInEntry entry : _testMixInInstances.values()) {
mixins.add(entry.getMixIn());
}
return Collections.unmodifiableList(mixins);
}
/**
* Get the "active" {@link TestMixIn} instance of the specified type.
*
* This method can only be called from inside a test method.
*
* @param type The {@link TestMixIn} type, as specified in the {@link SwitchYardTestCaseConfig} annotation.
* @param type {@link TestMixIn} type.
* @return The {@link TestMixIn} instance.
*/
public T getMixIn(Class type) {
if (_testMixInInstances == null || _testMixInInstances.isEmpty()) {
Assert.fail("No TestMixIns specified on Test class instance. Use the @TestMixIns annotation.");
}
if (_testMixInInstances.size() != getMixIns().size()) {
Assert.fail("TestMixIn instances only available during test method execution.");
}
MixInEntry mixIn = _testMixInInstances.get(type);
if (mixIn == null) {
Assert.fail("Required TestMixIn '" + type.getName() + "' is not specified on TestCase '" + _testInstance.getClass().getName() + "'.");
}
return type.cast(mixIn.getMixIn());
}
/**
* Returns required mixin dependencies.
*
* @param mixIn Mix in asking about dependencies.
* @return Dependencies which are mandatory for mixin
*/
public Set getRequiredDependencies(TestMixIn mixIn) {
return Collections.unmodifiableSet(_testMixInInstances.get(mixIn.getClass()).getRequiredDeps());
}
/**
* Returns optional mixin dependencies.
*
* @param mixIn Mix in asking about dependencies.
* @return Dependencies which are not mandatory for mixin
*/
public Set getOptionalDependencies(TestMixIn mixIn) {
return Collections.unmodifiableSet(_testMixInInstances.get(mixIn.getClass()).getOptionalDeps());
}
/**
* Finds a resource with a given name.
*
* Searches relative to the implementing class definition.
*
* @param name Name of the desired resource
* @return A {@link java.io.InputStream} object or null if no resource with this name is found.
*
* @see org.switchyard.common.type.Classes#getResourceAsStream(String,Class)
*/
public InputStream getResourceAsStream(String name) {
try {
return Classes.getResourceAsStream(name, _testInstance.getClass());
} catch (IOException ioe) {
return null;
}
}
/**
* Read a classpath resource and return as a byte array.
* @param path The path to the classpath resource. The specified path can be
* relative to the test class' location on the classpath.
* @return The resource as an array of bytes.
*/
public byte[] readResourceBytes(String path) {
if (path == null) {
Assert.fail("Resource 'path' not specified.");
}
InputStream resourceStream = getResourceAsStream(path);
if (resourceStream == null) {
Assert.fail("Resource '" + path + "' not found on classpath relative to test class '" + _testInstance.getClass().getName() + "'. May need to fix the relative path, or make the path absolute.");
}
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
try {
byte[] readBuffer = new byte[128];
int readCount = 0;
while ((readCount = resourceStream.read(readBuffer)) != -1) {
byteOutStream.write(readBuffer, 0, readCount);
}
} catch (IOException e) {
Assert.fail("Unexpected read error reading classpath resource '" + path + "'" + e.getMessage());
} finally {
try {
resourceStream.close();
} catch (IOException e) {
Assert.fail("Unexpected exception closing classpath resource '" + path + "'" + e.getMessage());
}
}
return byteOutStream.toByteArray();
}
/**
* Read a classpath resource and return as a String.
* @param path The path to the classpath resource. The specified path can be
* relative to the test class' location on the classpath.
* @return The resource as a String.
*/
public String readResourceString(String path) {
try {
return new String(readResourceBytes(path), "UTF-8");
} catch (UnsupportedEncodingException e) {
Assert.fail("Unexpected exception reading classpath resource '" + path + "' as a String. Perhaps this resource is a binary resource that cannot be encoded as a String." + e.getMessage());
return null; // Keep the compiler happy.
}
}
/**
* Read a classpath resource and return as an XML DOM Document.
*
* @param path The path to the classpath resource. The specified path can be
* relative to the test class' location on the classpath.
* @return The resource as a Document.
*/
public Document readResourceDocument(String path) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
return db.parse(getResourceAsStream(path));
} catch (Exception e) {
Assert.fail("Unexpected exception reading classpath resource '" + path + "' as a DOM Document." + e.getMessage());
return null; // Keep the compiler happy.
}
}
/**
* Load the SwitchYard configuration model specified by the configModel stream.
* @param configModel The config model stream.
* @return The SwitchYard config model.
*/
public SwitchYardModel loadSwitchYardModel(InputStream configModel) {
return loadSwitchYardModel(configModel, true);
}
/**
* Load the SwitchYard configuration model specified by the configModel stream.
* @param configModel The config model stream.
* @param validate Validate the model?
* @return The SwitchYard config model.
*/
public SwitchYardModel loadSwitchYardModel(InputStream configModel, boolean validate) {
return loadConfigModel(configModel, SwitchYardModel.class, validate);
}
/**
* Load the configuration model specified by the configModel stream.
* @param Model type.
* @param configModel The config model stream.
* @param modelType Model type.
* @return The config model.
*/
public M loadConfigModel(InputStream configModel, Class modelType) {
return loadConfigModel(configModel, modelType, true);
}
/**
* Load the SwitchYard configuration model specified by the configModel stream.
* @param Model type.
* @param configModel The config model stream.
* @param modelType Model type.
* @param validate Validate the model?
* @return The SwitchYard config model.
*/
public M loadConfigModel(InputStream configModel, Class modelType, boolean validate) {
if (configModel == null) {
throw new IllegalArgumentException("null 'configModel' arg.");
}
try {
M pulledModel = new ModelPuller().pull(configModel);
if (validate) {
pulledModel.assertModelValid();
}
return pulledModel;
} catch (IOException e) {
Assert.fail("Unexpected error building " + modelType.getSimpleName() + ": " + e.getMessage());
} finally {
try {
configModel.close();
} catch (IOException e) {
Assert.fail("Unexpected error closing " + modelType.getSimpleName() + " stream: " + e.getMessage());
}
}
return null;
}
/**
* Compare an XML string (e.g. a result) against a classpath resource.
* @param xml The XML (as a String) to be compared against the XML in the specified
* classpath resource.
* @param resourcePath The path to the classpath resource against which the XML is to be
* compared. The specified path can be relative to the test class' location on the classpath.
*/
public void compareXMLToResource(String xml, String resourcePath) {
XMLUnit.setIgnoreWhitespace(true);
try {
XMLAssert.assertXMLEqual(readResourceString(resourcePath), xml);
} catch (Exception e) {
Assert.fail("Unexpected error performing XML comparison: " + e.getMessage());
}
}
/**
* Compare an XML String (e.g. a result) against another String.
* @param xml The XML (as a String) to be compared against the XML in the specified
* classpath resource.
* @param string The String against which the XML is to be
* compared.
*/
public static void compareXMLToString(String xml, String string) {
XMLUnit.setIgnoreWhitespace(true);
try {
XMLAssert.assertXMLEqual(string, xml);
} catch (Exception e) {
Assert.fail("Unexpected error performing XML comparison.");
}
}
/**
* Enables message tracing for the application under test.
* @param doTrace true to enable message tracing, false to disable
*/
public void traceMessages(boolean doTrace) {
getServiceDomain().setProperty(MessageTraceHandler.TRACE_ENABLED, true);
}
/**
* invoke the methods annotated with {@link BeforeDeploy} on test class.
*/
private void beforeDeploy() throws Exception {
Method[] publicMethods = _testInstance.getClass().getMethods();
for (Method method : publicMethods) {
BeforeDeploy beforeAnno = method.getAnnotation(BeforeDeploy.class);
if (beforeAnno != null) {
method.invoke(_testInstance);
}
}
}
/**
* Create and initialise the deployment.
* @throws Exception creating the deployment.
*/
private final void deploy() throws Exception {
_deployment = createDeployment();
ServiceDomain domain = new ServiceDomainManager().createDomain(
ServiceDomainManager.ROOT_DOMAIN, _deployment.getConfig());
_activators = ActivatorLoader.createActivators(domain);
SwitchYardTestCaseConfig testCaseConfig = _testInstance.getClass().getAnnotation(SwitchYardTestCaseConfig.class);
if (testCaseConfig != null) {
// Process includes...
Collection includes = new HashSet(Arrays.asList(testCaseConfig.include()));
if (!includes.isEmpty()) {
Iterator activatorsIt = _activators.iterator();
while (activatorsIt.hasNext()) {
Activator activator = activatorsIt.next();
// If the activator does not specify one of the include types, then remove it...
if (!intersection(includes, activator.getActivationTypes())) {
activatorsIt.remove();
}
}
}
// Process excludes...
Collection excludes = new HashSet(Arrays.asList(testCaseConfig.exclude()));
if (!excludes.isEmpty()) {
Iterator activatorsIt = _activators.iterator();
while (activatorsIt.hasNext()) {
Activator activator = activatorsIt.next();
// If the activator specifies one of the exclude types, then remove it...
if (intersection(excludes, activator.getActivationTypes())) {
activatorsIt.remove();
}
}
}
}
_deployment.init(domain, _activators);
mixInBefore();
_deployment.setFailOnMissingActivator(false); // It's OK to have a "missing" activator for a test, so we don't want to fail.
_deployment.start();
}
/**
* Undeploy the deployment.
*/
private final void undeploy() {
assertDeployed();
_deployment.stop();
mixInAfter();
_deployment.destroy();
}
/**
* Create the deployment instance.
* @return The deployment instance.
* @throws Exception creating the deployment.
*/
private AbstractDeployment createDeployment() throws Exception {
if (_configModel != null) {
return new Deployment(_configModel);
} else {
return new SimpleTestDeployment();
}
}
private void initializeMixIns() {
for (TestMixIn mixIn : getMixIns()) {
mixIn.initialize();
}
}
private void mixInBefore() {
for (TestMixIn mixIn : getMixIns()) {
mixIn.before(_deployment);
}
}
private void mixInAfter() {
// Apply after MixIns in reverse order...
List mixins = new ArrayList(getMixIns());
Collections.reverse(mixins);
for (TestMixIn mixIn : mixins) {
mixIn.after(_deployment);
}
}
private void cleanupMixIns() {
// Destroy MixIns in reverse order...
List mixins = new ArrayList(getMixIns());
Collections.reverse(mixins);
for (TestMixIn mixIn : mixins) {
mixIn.uninitialize();
}
}
private void createMixInInstances() {
if (_testMixInInstances == null || _testMixInInstances.isEmpty()) {
// No Mix-Ins...
return;
}
Set> mixinClasses = new LinkedHashSet>(
_testMixInInstances.keySet());
for (Class extends TestMixIn> mixInType : mixinClasses) {
createMixInRecursively(mixInType);
}
}
private MixInEntry createMixInRecursively(Class extends TestMixIn> mixInType) {
if (_testMixInInstances.containsKey(mixInType) && _testMixInInstances.get(mixInType) != null) {
return _testMixInInstances.get(mixInType);
}
Set requiredDeps = new LinkedHashSet();
Set optionalDeps = new LinkedHashSet();
// create dependencies first
MixInDependencies dependencies = mixInType.getAnnotation(MixInDependencies.class);
if (dependencies != null) {
Class extends TestMixIn>[] activeDependencies = dependencies.required();
if (activeDependencies != null && activeDependencies[0] != NullMixIns.class) {
for (Class extends TestMixIn> mixin : activeDependencies) {
MixInEntry dependency = createMixInRecursively(mixin);
requiredDeps.add(dependency.getMixIn());
_testMixInInstances.put(mixin, dependency);
}
}
Class extends TestMixIn>[] passiveDependencies = dependencies.optional();
if (passiveDependencies != null && passiveDependencies[0] != NullMixIns.class) {
for (Class extends TestMixIn> mixin : passiveDependencies) {
if (_testMixInInstances.containsKey(mixin)) {
MixInEntry dependency = createMixInRecursively(mixin);
optionalDeps.add(dependency.getMixIn());
_testMixInInstances.put(mixin, dependency);
}
}
}
}
TestMixIn testMixIn = newMixInInstance(mixInType, _testInstance);
testMixIn.setTestKit(this);
MixInEntry entry = new MixInEntry(testMixIn, requiredDeps, optionalDeps);
// here is where whole trick is done - we must move created mixin after
// it's dependencies, so we remove entry and add same instance once again
_testMixInInstances.remove(mixInType);
_testMixInInstances.put(mixInType, entry);
return entry;
}
protected static T newMixInInstance(Class mixInType, Object testInstance) {
Class extends Object> testClass = testInstance.getClass();
Method[] methods = testClass.getDeclaredMethods();
// Check for a factory method for the MixIn type...
for (Method method : methods) {
int modifiers = method.getModifiers();
if (Modifier.isPublic(modifiers)) {
if (method.getReturnType() == mixInType && method.getParameterTypes().length == 0) {
try {
if (Modifier.isStatic(modifiers)) {
return mixInType.cast(method.invoke(null));
} else {
return mixInType.cast(method.invoke(testInstance));
}
} catch (Exception e) {
e.printStackTrace();
Assert.fail("Failed to create instance of TestMixIn type " + mixInType.getName() + ". Error invoking the MixIn factory method '" + method.getName() + "': " + e.getMessage());
return null;
}
}
}
}
try {
return mixInType.newInstance();
} catch (Exception e) {
e.printStackTrace();
Assert.fail("Failed to create instance of TestMixIn type " + mixInType.getName() + " via public default constructor: " + e.getMessage());
return null;
}
}
private SwitchYardModel createSwitchYardModel(InputStream configModel, List> scanners, boolean validate) {
Assert.assertNotNull("Test 'configModel' is null.", configModel);
final SwitchYardModel returnModel;
try {
SwitchYardModel model = loadSwitchYardModel(configModel, false);
ClassLoader classLoader = _testInstance.getClass().getClassLoader();
if (scanners != null && !scanners.isEmpty() && classLoader instanceof URLClassLoader) {
String uri = model.getModelRootNamespace();
SwitchYardNamespace ns = SwitchYardNamespace.fromUri(uri);
MergeScanner merge_scanner = new MergeScanner(true, scanners);
List scanURLs = getScanURLs((URLClassLoader)classLoader);
ScannerInput scanner_input = new ScannerInput()
.setSwitchyardNamespace(ns).setCompositeName(model.getName()).setURLs(scanURLs);
V1SwitchYardModel scannedModel = merge_scanner.scan(scanner_input).getModel();
returnModel = Models.merge(scannedModel, model, false);
} else {
returnModel = model;
}
if (validate) {
returnModel.assertModelValid();
}
return returnModel;
} catch (java.io.IOException ioEx) {
throw new SwitchYardException("Failed to read switchyard config.", ioEx);
}
}
private void assertDeployed() {
if (_deployment == null) {
Assert.fail("TestCase deployment not yet deployed. You may need to make an explicit call to the deploy() method.");
}
}
private List> createScanners(SwitchYardTestCaseConfig testCaseConfig) {
List> scanners = new ArrayList>();
if (testCaseConfig != null) {
Class extends Scanner>[] scannerClasses = testCaseConfig.scanners();
if (scannerClasses == null) {
// No Scanners
_logger.debug("No Scanners for test.");
} else if (scannerClasses.length == 1 && scannerClasses[0] == NullScanners.class) {
// No Scanners
_logger.debug("No Scanners for test.");
} else {
for (Class extends Scanner> scannerClass : scannerClasses) {
try {
scanners.add(scannerClass.newInstance());
} catch (Exception e) {
Assert.fail("Exception creating instance of Scanner class '" + scannerClass.getName() + "': " + e.getMessage());
}
}
}
}
return scanners;
}
private List getScanURLs(URLClassLoader classLoader) {
URL[] classPathURLs = classLoader.getURLs();
List scanURLs = new ArrayList();
// Only scan directories. Above all, we want to make sure we don't
// start scanning JDK jars etc...
for (URL classpathURL : classPathURLs) {
try {
File file = ClasspathScanner.toClassPathFile(classpathURL);
if (file.isDirectory()) {
scanURLs.add(classpathURL);
}
} catch (IOException e) {
Assert.fail("Failed to convert classpath URL '" + classpathURL + "' to a File instance.");
}
}
// Temp hack to work around SWITCHYARD-343 (https://issues.jboss.org/browse/SWITCHYARD-343)...
if (scanURLs.isEmpty()) {
try {
scanURLs.add(new File("target/test-classes").toURI().toURL());
scanURLs.add(new File("target/classes").toURI().toURL());
} catch (MalformedURLException e) {
Assert.fail("Unexpected exception adding target test classes folders to test scan URLs: " + e.getMessage());
}
}
return scanURLs;
}
private boolean intersection(Collection set1, Collection set2) {
if (set1.isEmpty() || set2.isEmpty()) {
return false;
}
Collection set1Copy = new HashSet(set1);
set1Copy.removeAll(set2);
// If entries were removed from the set then we have an intersect, otherwise we don't...
return (set1Copy.size() < set1.size());
}
@Scannable(false)
private static final class TransformerWrapper extends BaseTransformer {
private Transformer _transformer;
private TransformModel _transformModel;
private TransformerWrapper(Transformer transformer, TransformModel transformModel) {
this._transformer = transformer;
this._transformModel = transformModel;
}
@Override
public Object transform(Object from) {
return _transformer.transform(from);
}
@Override
public QName getFrom() {
return _transformModel.getFrom();
}
@Override
public QName getTo() {
return _transformModel.getTo();
}
}
/**
* Hidden marker type to provide a valid NULL
* Scanners configuration for {@link SwitchYardTestCaseConfig}.
*/
protected static final class NullScanners implements Scanner {
@Override
public ScannerOutput scan(ScannerInput scannerInput) throws IOException {
return null;
}
}
/**
* Hidden marker type to provide a valid NULL
* TestMixIns configuration for {@link SwitchYardTestCaseConfig}.
*/
protected static final class NullMixIns extends AbstractTestMixIn {
}
/**
* Helper class to keep mixin and it's dependencies.
*
*/
protected static class MixInEntry {
private final TestMixIn _mixin;
private Set _requiredDeps;
private Set _optionalDeps;
public MixInEntry(TestMixIn mixin, Set requiredDeps, Set optionalDeps) {
this._mixin = mixin;
this._requiredDeps = requiredDeps;
this._optionalDeps = optionalDeps;
}
public TestMixIn getMixIn() {
return _mixin;
}
public Set getRequiredDeps() {
return _requiredDeps;
}
public Set getOptionalDeps() {
return _optionalDeps;
}
}
}