package com.epam.wilma.stubconfig.initializer.support;
/*==========================================================================
Copyright 2013-2017 EPAM Systems
This file is part of Wilma.
Wilma is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Wilma is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Wilma. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
import java.io.File;
import java.util.Collection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.epam.wilma.common.helper.FileFactory;
import com.epam.wilma.common.helper.FileUtils;
import com.epam.wilma.domain.stubconfig.exception.DescriptorValidationFailedException;
import com.epam.wilma.stubconfig.initializer.condition.helper.ClassPathExtender;
import com.epam.wilma.stubconfig.initializer.support.helper.BeanRegistryService;
import com.epam.wilma.stubconfig.initializer.support.helper.ClassInstantiator;
import com.epam.wilma.stubconfig.initializer.support.helper.PackageBasedClassFinder;
/**
* Initializes classes from jars.
* @author Adam_Csaba_Kiraly
*
*/
@Component
public class ExternalJarClassInitializer {
private static final String GOT_BEAN_TEMPLATE = "Got bean of name: '{}' , type: '{}' and interface: {}";
private static final String JAR_INITIALIZATION_TEMPLATE = "JAR - Initialized class '{}' of '{}' interface, using folder path '{}'.";
private final Logger logger = LoggerFactory.getLogger(ExternalJarClassInitializer.class);
@Autowired
private ClassPathExtender classPathExtender;
@Autowired
private PackageBasedClassFinder packageBasedClassFinder;
@Autowired
private FileUtils fileUtils;
@Autowired
private ClassInstantiator classInstantiator;
@Autowired
private FileFactory fileFactory;
@Autowired
private BeanRegistryService beanRegistryService;
/**
* Imports external class from the file system and adds it to the class path.
* @param <T> is the type of the return object
* @param packageName is the package name of the class to be loaded
* @param jarFolderPath is the path where jars are placed when uploaded
* @param interfaceToCast class of the desirable interface
* @return with the new instance of the class
* @throws DescriptorValidationFailedException if the class does not exist or not valid.
*/
public <T> T loadExternalClass(final String packageName, final String jarFolderPath, final Class<T> interfaceToCast) {
String beanName = createBeanName(packageName, interfaceToCast);
T result;
try {
result = beanRegistryService.getBean(beanName, interfaceToCast);
logger.info(GOT_BEAN_TEMPLATE, beanName, result.getClass().getName(), interfaceToCast);
} catch (BeansException e) {
logger.debug(String.format("Finding bean with name '%s' of type '%s' failed", beanName, interfaceToCast), e);
result = initializeFromJars(packageName, jarFolderPath, interfaceToCast);
beanRegistryService.register(beanName, result);
}
return result;
}
private <T> T initializeFromJars(final String packageName, final String jarFolderPath, final Class<T> interfaceToCast) {
T result;
try {
addJarFilesInFolderPathToClassPath(jarFolderPath);
Class<? extends T> classToLoad = packageBasedClassFinder.findFirstOf(interfaceToCast, packageName);
result = classInstantiator.createClassInstanceOf(classToLoad);
logger.info(JAR_INITIALIZATION_TEMPLATE, classToLoad.getName(), interfaceToCast.getName(), jarFolderPath);
} catch (SecurityException | IllegalArgumentException | ReflectiveOperationException | NoClassDefFoundError e) {
throw new DescriptorValidationFailedException(
"Validation of stub descriptor failed - Referenced class not found: '" + packageName + "'.", e);
} catch (ClassFormatError e) {
throw new DescriptorValidationFailedException("Validation of stub descriptor failed - Invalid format: '" + packageName + "'.", e);
}
return result;
}
private void addJarFilesInFolderPathToClassPath(final String jarFolderPath) {
Collection<File> files = fileUtils.listFiles(fileFactory.createFile(jarFolderPath), "jar");
for (File fileElement : files) {
classPathExtender.addFile(fileElement.getPath());
}
}
private <T> String createBeanName(final String name, final Class<T> interfaceToCast) {
return name + interfaceToCast.getSimpleName();
}
}