io.atlasmap.core.DefaultAtlasContextFactory Maven / Gradle / Ivy
/**
* Copyright (C) 2017 Red Hat, Inc.
*
* 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 io.atlasmap.core;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Constructor;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.atlasmap.api.AtlasContext;
import io.atlasmap.api.AtlasContextFactory;
import io.atlasmap.api.AtlasException;
import io.atlasmap.api.AtlasValidationService;
import io.atlasmap.mxbean.AtlasContextFactoryMXBean;
import io.atlasmap.spi.AtlasCombineStrategy;
import io.atlasmap.spi.AtlasConversionService;
import io.atlasmap.spi.AtlasFieldActionService;
import io.atlasmap.spi.AtlasModule;
import io.atlasmap.spi.AtlasModuleDetail;
import io.atlasmap.spi.AtlasModuleInfo;
import io.atlasmap.spi.AtlasModuleInfoRegistry;
import io.atlasmap.spi.AtlasPropertyStrategy;
import io.atlasmap.spi.AtlasSeparateStrategy;
import io.atlasmap.v2.AtlasMapping;
public class DefaultAtlasContextFactory implements AtlasContextFactory, AtlasContextFactoryMXBean {
private static final Logger LOG = LoggerFactory.getLogger(DefaultAtlasContextFactory.class);
private static DefaultAtlasContextFactory factory = null;
private boolean initialized = false;
private String uuid = null;
private String threadName = null;
private ObjectName objectName = null;
private AtlasMappingService atlasMappingService = null;
private DefaultAtlasConversionService atlasConversionService = null;
private DefaultAtlasFieldActionService atlasFieldActionService = null;
private AtlasCombineStrategy atlasCombineStrategy = new DefaultAtlasCombineStrategy();
private AtlasPropertyStrategy atlasPropertyStrategy = new DefaultAtlasPropertyStrategy();
private AtlasSeparateStrategy atlasSeparateStrategy = new DefaultAtlasSeparateStrategy();
private AtlasValidationService atlasValidationService = new DefaultAtlasValidationService();
private AtlasModuleInfoRegistry moduleInfoRegistry;
private Map properties = null;
private CompoundClassLoader classLoader = null;
private DefaultAtlasContextFactory() {
}
public static DefaultAtlasContextFactory getInstance() {
if (factory == null) {
factory = new DefaultAtlasContextFactory();
factory.init();
}
return factory;
}
@Override
public synchronized void init() {
if (this.initialized) {
return;
}
this.uuid = UUID.randomUUID().toString();
this.threadName = Thread.currentThread().getName();
this.classLoader = new CompoundClassLoader();
this.classLoader.add(AtlasMapping.class.getClassLoader());
this.atlasConversionService = DefaultAtlasConversionService.getInstance();
this.atlasFieldActionService = DefaultAtlasFieldActionService.getInstance();
this.atlasFieldActionService.init(this.classLoader);
registerFactoryJmx(this);
this.moduleInfoRegistry = new DefaultAtlasModuleInfoRegistry(this);
loadModules("moduleClass", AtlasModule.class);
setMappingService(new AtlasMappingService(this.classLoader));
this.initialized = true;
}
@Override
public void setProperties(Map properties) {
this.properties = properties;
}
@Override
public void setProperties(Properties properties) {
this.properties = new HashMap<>();
properties.forEach((key, value) -> this.properties.put(key.toString(), value.toString()));
}
@Override
public Map getProperties() {
return this.properties;
}
@Override
public synchronized void destroy() {
if (!this.initialized) {
return;
}
unloadModules();
try {
if (ManagementFactory.getPlatformMBeanServer().isRegistered(getJmxObjectName())) {
ManagementFactory.getPlatformMBeanServer().unregisterMBean(getJmxObjectName());
if (LOG.isDebugEnabled()) {
LOG.debug("Unregistered AtlasContextFactory with JMX");
}
}
} catch (Exception e) {
LOG.warn("Unable to unregister with JMX", e);
}
this.uuid = null;
this.objectName = null;
this.properties = null;
this.atlasMappingService = null;
this.atlasFieldActionService = null;
this.atlasConversionService = null;
this.atlasPropertyStrategy = null;
this.moduleInfoRegistry = null;
this.classLoader = null;
this.threadName = null;
this.initialized = false;
factory = null;
}
@Override
public AtlasContext createContext(File atlasMappingFile) throws AtlasException {
if (atlasMappingFile == null) {
throw new AtlasException("AtlasMappingFile must be specified");
}
return createContext(atlasMappingFile.toURI());
}
@Override
public AtlasContext createContext(URI atlasMappingUri) throws AtlasException {
if (atlasMappingUri == null) {
throw new AtlasException("AtlasMappingUri must be specified");
}
if (getMappingService() == null) {
throw new AtlasException("AtlasMappingService is not set");
}
DefaultAtlasContext context = new DefaultAtlasContext(this, atlasMappingUri);
context.init();
return context;
}
public AtlasContext createContext(AtlasMapping mapping) throws AtlasException {
DefaultAtlasContext context = new DefaultAtlasContext(this, mapping);
context.init();
return context;
}
@Override
public String getClassName() {
return this.getClass().getName();
}
@Override
public String getThreadName() {
return this.threadName;
}
public void setThreadName(String threadName) {
this.threadName = threadName;
}
@Override
public String getVersion() {
return this.getClass().getPackage().getImplementationVersion();
}
@Override
public String getUuid() {
return this.uuid;
}
public ObjectName getJmxObjectName() {
return this.objectName;
}
public AtlasMappingService getMappingService() {
return this.atlasMappingService;
}
public void setMappingService(AtlasMappingService atlasMappingService) {
this.atlasMappingService = atlasMappingService;
}
public AtlasModuleInfoRegistry getModuleInfoRegistry() {
return this.moduleInfoRegistry;
}
public void setModuleInfoRegistry(AtlasModuleInfoRegistry registry) {
this.moduleInfoRegistry = registry;
}
@Override
public AtlasConversionService getConversionService() {
return this.atlasConversionService;
}
@Override
public AtlasFieldActionService getFieldActionService() {
return this.atlasFieldActionService;
}
@Override
public AtlasCombineStrategy getCombineStrategy() {
return atlasCombineStrategy;
}
public void setCombineStrategy(AtlasCombineStrategy atlasCombineStrategy) {
this.atlasCombineStrategy = atlasCombineStrategy;
}
@Override
public AtlasPropertyStrategy getPropertyStrategy() {
return atlasPropertyStrategy;
}
public void setPropertyStrategy(AtlasPropertyStrategy atlasPropertyStrategy) {
this.atlasPropertyStrategy = atlasPropertyStrategy;
}
@Override
public AtlasSeparateStrategy getSeparateStrategy() {
return atlasSeparateStrategy;
}
public void setSeparateStrategy(AtlasSeparateStrategy atlasSeparateStrategy) {
this.atlasSeparateStrategy = atlasSeparateStrategy;
}
@Override
public AtlasValidationService getValidationService() {
return atlasValidationService;
}
public void setValidationService(AtlasValidationService atlasValidationService) {
this.atlasValidationService = atlasValidationService;
}
public CompoundClassLoader getClassLoader() {
return this.classLoader;
}
public void addClassLoader(ClassLoader cl) {
this.classLoader.add(cl);
}
protected void loadModules(String moduleClassProperty, Class> moduleInterface) {
Class> moduleClass = null;
String moduleClassName = null;
Set serviceClasses = new HashSet<>();
try {
Enumeration urls = classLoader.getResources("META-INF/services/atlas/module/atlas.module");
while (urls.hasMoreElements()) {
URL tmp = urls.nextElement();
Properties prop = AtlasUtil.loadPropertiesFromURL(tmp);
String serviceClassPropertyValue = (String) prop.get(moduleClassProperty);
String[] splitted = serviceClassPropertyValue != null ? serviceClassPropertyValue.split(",") : new String[0];
for (String entry : splitted) {
if (!AtlasUtil.isEmpty(entry)) {
serviceClasses.add((entry));
}
}
}
} catch (Exception e) {
LOG.warn("Error loading module resources", e);
}
for (String clazz : serviceClasses) {
try {
moduleClass = classLoader.loadClass(clazz);
moduleClassName = moduleClass.getName();
if (isClassAtlasModule(moduleClass, moduleInterface)) {
@SuppressWarnings("unchecked")
Class atlasModuleClass = (Class)moduleClass;
Constructor constructor = atlasModuleClass.getDeclaredConstructor();
if (constructor != null) {
AtlasModuleInfo module = new DefaultAtlasModuleInfo(getModuleName(moduleClass),
getModuleUri(moduleClass), atlasModuleClass, constructor,
getSupportedDataFormats(moduleClass), getConfigPackages(moduleClass));
getModuleInfoRegistry().register(module);
} else {
LOG.warn("Invalid module class {}: constructor is not present", moduleClassName);
}
} else {
LOG.warn("Invalid module class {}: unsupported AtlasModule", moduleClassName);
}
} catch (NoSuchMethodException e) {
LOG.warn(String.format("Invalid module class %s: constructor is not present.", moduleClassName), e);
} catch (ClassNotFoundException e) {
LOG.warn(String.format("Invalid module class %s: not found in classLoader.", moduleClassName), e);
} catch (Exception e) {
LOG.warn(String.format("Invalid module class %s: unknown error.", moduleClassName), e);
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("Loaded: {} of {} detected modules", getModuleInfoRegistry().size(), serviceClasses.size());
}
}
protected void unloadModules() {
if (getModuleInfoRegistry() == null) {
return;
}
int moduleCount = getModuleInfoRegistry().size();
getModuleInfoRegistry().unregisterAll();
if (LOG.isDebugEnabled()) {
LOG.debug("Unloaded: {} modules", moduleCount);
}
}
protected boolean isClassAtlasModule(Class> clazz, Class> moduleInterface) {
if (clazz == null) {
return false;
}
if (isAtlasModuleInterface(clazz, moduleInterface) && clazz.isAnnotationPresent(AtlasModuleDetail.class)) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} is a '{}' implementation", clazz.getCanonicalName(), moduleInterface.getSimpleName());
}
return true;
}
if (LOG.isDebugEnabled()) {
LOG.debug("{} is NOT a '{}' implementation", clazz.getCanonicalName(), moduleInterface.getSimpleName());
}
return false;
}
protected boolean isAtlasModuleInterface(Class> clazz, Class> moduleInterface) {
if (clazz == null) {
return false;
}
boolean isIface = false;
Class> superClazz = clazz.getSuperclass();
if (superClazz != null) {
isIface = isAtlasModuleInterface(superClazz, moduleInterface);
}
Class>[] interfaces = clazz.getInterfaces();
for (Class> iface : interfaces) {
if (iface.equals(moduleInterface)) {
isIface = true;
}
}
return isIface;
}
protected String getModuleUri(Class> clazz) {
AtlasModuleDetail detail = clazz.getAnnotation(AtlasModuleDetail.class);
if (detail != null) {
return detail.uri();
}
return "UNDEFINED";
}
protected String getModuleName(Class> clazz) {
AtlasModuleDetail detail = clazz.getAnnotation(AtlasModuleDetail.class);
if (detail != null) {
return detail.name();
}
return "UNDEFINED-" + UUID.randomUUID().toString();
}
protected List getSupportedDataFormats(Class> clazz) {
List dataFormats = null;
AtlasModuleDetail detail = clazz.getAnnotation(AtlasModuleDetail.class);
if (detail != null) {
dataFormats = new ArrayList<>();
String[] formats = detail.dataFormats();
for (String format : formats) {
dataFormats.add(format.trim());
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("Module: {} supports data formats: {}", clazz.getCanonicalName(), dataFormats);
}
return dataFormats;
}
protected List getConfigPackages(Class> clazz) {
List configPackages = null;
AtlasModuleDetail detail = clazz.getAnnotation(AtlasModuleDetail.class);
if (detail != null) {
configPackages = new ArrayList<>();
String[] packages = detail.configPackages();
for (String pkg : packages) {
configPackages.add(pkg.trim());
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("Module: {} config packages: {}", clazz.getCanonicalName(), configPackages);
}
return configPackages;
}
protected List getAllModuleConfigPackages(AtlasModuleInfoRegistry registry) {
List pkgs = new ArrayList<>();
for (AtlasModuleInfo moduleInfo : registry.getAll()) {
pkgs.addAll(Arrays.asList(moduleInfo.getPackageNames()));
}
return pkgs;
}
protected void registerFactoryJmx(DefaultAtlasContextFactory factory) {
if (factory == null) {
return;
}
try {
factory.setObjectName();
if (!ManagementFactory.getPlatformMBeanServer().isRegistered(factory.getJmxObjectName())) {
ManagementFactory.getPlatformMBeanServer().registerMBean(factory, factory.getJmxObjectName());
if (LOG.isDebugEnabled()) {
LOG.debug("Registered AtlasContextFactory with JMX");
}
}
} catch (Exception e) {
LOG.warn("Unable to resgister DefaultAtlasContextFactory with JMX", e);
}
}
protected void setObjectName() throws MalformedObjectNameException {
this.objectName = new ObjectName(String.format("io.atlasmap:type=AtlasServiceFactory,factoryUuid=%s", getUuid()));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy