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

org.datacleaner.descriptors.RemoteDescriptorProviderImpl Maven / Gradle / Ivy

/**
 * DataCleaner (community edition)
 * Copyright (C) 2014 Neopost - Customer Information Management
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program 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 Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.datacleaner.descriptors;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.lang.ClassUtils;
import org.apache.metamodel.util.LazyRef;
import org.datacleaner.Version;
import org.datacleaner.configuration.RemoteServerConfiguration;
import org.datacleaner.configuration.RemoteServerData;
import org.datacleaner.configuration.RemoteServerState;
import org.datacleaner.configuration.RemoteServerStateListener;
import org.datacleaner.restclient.ComponentList;
import org.datacleaner.restclient.ComponentRESTClient;
import org.datacleaner.restclient.Serializator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;

/**
 * Provides descriptors of components that are available for remote calls on a
 * DataCleaner Monitor server. The list of them is downloaded and appropriate
 * descriptors are created for them ({@link RemoteTransformerDescriptorImpl}).
 *
 * @Since 9/8/15
 */
public class RemoteDescriptorProviderImpl extends AbstractDescriptorProvider implements RemoteDescriptorProvider {

    private final class RemoteLazyRef extends LazyRef {
        @Override
        public Data fetch() throws Throwable {
            final Data data = new Data();
            data.downloadDescriptors();

            return data;
        }
    }

    private final class Data {
        final Map> _analyzerBeanDescriptors = new HashMap<>();
        final Map> _filterBeanDescriptors = new HashMap<>();
        final Map> _transformerBeanDescriptors = new HashMap<>();
        final Map> _rendererBeanDescriptors = new HashMap<>();

        private void downloadDescriptors() {
            try {
                logger.info("Loading remote components list from " + remoteServerData.getUrl());
                final ComponentRESTClient client =
                        new ComponentRESTClient(remoteServerData.getUrl(), remoteServerData.getUsername(),
                                remoteServerData.getPassword(), Version.getVersion());
                final ComponentList components = client.getAllComponents(true);

                for (final ComponentList.ComponentInfo component : components.getComponents()) {
                    try {
                        final RemoteTransformerDescriptorImpl transformerDescriptor =
                                new RemoteTransformerDescriptorImpl(RemoteDescriptorProviderImpl.this,
                                        component.getName(),
                                        initAnnotations(component.getName(), null, component.getAnnotations()),
                                        component.getIconData(), component.isEnabled());
                        for (final Map.Entry propE : component.getProperties()
                                .entrySet()) {
                            final String propertyName = propE.getKey();
                            final ComponentList.PropertyInfo propInfo = propE.getValue();
                            final String className = propInfo.getClassName();
                            try {
                                final Class cl = findClass(className);
                                transformerDescriptor.addPropertyDescriptor(
                                        new TypeBasedConfiguredPropertyDescriptorImpl(propertyName,
                                                propInfo.getDescription(), cl, propInfo.isRequired(),
                                                transformerDescriptor,
                                                initAnnotations(component.getName(), propertyName,
                                                        propInfo.getAnnotations()), propInfo.getDefaultValue()));
                            } catch (final ClassNotFoundException e) {
                                logger.debug("Cannot initialize typed property descriptor '{}'.'{}' because of {}",
                                        component.getName(), propertyName, e.toString());
                                // class not available on this server.
                                transformerDescriptor.addPropertyDescriptor(
                                        new JsonSchemaConfiguredPropertyDescriptorImpl(propertyName,
                                                propInfo.getSchema(), propInfo.isInputColumn(),
                                                propInfo.getDescription(), propInfo.isRequired(), transformerDescriptor,
                                                initAnnotations(component.getName(), propertyName,
                                                        propInfo.getAnnotations()), propInfo.getDefaultValue()));
                            }
                        }
                        _transformerBeanDescriptors.put(transformerDescriptor.getDisplayName(), transformerDescriptor);
                        logger.info("Registered remote component {}", transformerDescriptor.getDisplayName());
                    } catch (final Exception e) {
                        logger.error("Cannot create remote component representation for: " + component.getName(), e);
                    }
                }
            } catch (final Exception e) {
                logger.error("Cannot get list of remote components on " + remoteServerData.getUrl(), e);
                // TODO: plan a task to try again after somw while. And then
                // notify listeners...
            }
        }
    }

    private class RemoteServerStateListenerImpl implements RemoteServerStateListener {

        @Override
        public void onRemoteServerStateChange(final String remoteServerName, final RemoteServerState state) {
            if (remoteServerName.equals(remoteServerData.getServerName())) {
                actualState = state;
            }
        }
    }

    private static final Logger logger = LoggerFactory.getLogger(RemoteDescriptorProviderImpl.class);
    private final RemoteServerData remoteServerData;
    private final RemoteServerConfiguration remoteServerConfiguration;
    private RemoteLazyRef dataLazyReference = new RemoteLazyRef();
    private RemoteServerState actualState = null;
    private RemoteServerStateListener remoteServerStateListener = new RemoteServerStateListenerImpl();

    public RemoteDescriptorProviderImpl(final RemoteServerData remoteServerData,
            final RemoteServerConfiguration remoteServerConfiguration) {
        super(false);
        this.remoteServerData = remoteServerData;
        this.remoteServerConfiguration = remoteServerConfiguration;
        dataLazyReference.requestLoad();
    }

    @Override
    public RemoteServerData getServerData() {
        return remoteServerData;
    }

    public RemoteServerState getServerState() {
        if (actualState == null) {
            remoteServerConfiguration.addListener(remoteServerStateListener);
            actualState = remoteServerConfiguration.getActualState(remoteServerData.getServerName());
        }
        return actualState;
    }

    public void refresh() {
        dataLazyReference = new RemoteLazyRef();
        notifyListeners();
    }

    @Override
    public Collection> getFilterDescriptors() {
        return Collections.unmodifiableCollection(dataLazyReference.get()._filterBeanDescriptors.values());
    }

    @Override
    public Collection> getAnalyzerDescriptors() {
        return Collections.unmodifiableCollection(dataLazyReference.get()._analyzerBeanDescriptors.values());
    }

    @Override
    public Collection> getTransformerDescriptors() {
        return Collections.unmodifiableCollection(dataLazyReference.get()._transformerBeanDescriptors.values());
    }

    @Override
    public Collection> getRendererBeanDescriptors() {
        return Collections.unmodifiableCollection(dataLazyReference.get()._rendererBeanDescriptors.values());
    }

    private Class findClass(final String name) throws ClassNotFoundException {
        return ClassUtils.getClass(getClass().getClassLoader(), name, false);
    }

    private Map, Annotation> initAnnotations(final String componentName,
            final String propertyName, final JsonNode annotationsInfo) {
        final Map, Annotation> annotations = new HashMap<>();
        if (annotationsInfo == null) {
            return annotations;
        }

        for (final Iterator> it = annotationsInfo.fields(); it.hasNext(); ) {
            final Map.Entry annotationEntry = it.next();
            try {
                final String annotClassName = annotationEntry.getKey();
                @SuppressWarnings("unchecked") final Class anClass =
                        (Class) Class.forName(annotClassName);

                final Map annotationValues = new HashMap<>();
                final JsonNode annProperties = annotationEntry.getValue();
                final Iterator> annPropIter = annProperties.fields();
                for (; annPropIter.hasNext(); ) {
                    final Map.Entry annPropEntry = annPropIter.next();
                    final String propName = annPropEntry.getKey();
                    final JsonNode propValueNode = annPropEntry.getValue();
                    final Method propMethod = anClass.getDeclaredMethod(propName, new Class[0]);
                    final Class propClass = propMethod.getReturnType();
                    final Object propValue =
                            Serializator.getJacksonObjectMapper().treeToValue(propValueNode, propClass);
                    annotationValues.put(propName, propValue);
                }

                final Annotation anProxy = AnnotationProxy.newAnnotation(anClass, annotationValues);
                annotations.put(anClass, anProxy);

            } catch (final Exception e) {
                if (propertyName == null) {
                    logger.warn("Cannot create annotation '{}' for component '{}' property '{}'",
                            annotationEntry.getKey(), componentName, propertyName, e);
                } else {
                    logger.warn("Cannot create annotation '{}' for component '{}'", annotationEntry.getKey(),
                            componentName, e);
                }
            }
        }
        return annotations;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy