org.datacleaner.guice.DCModuleImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.datacleaner.guice.DCModuleImpl.java

Source

/**
 * 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.guice;

import java.io.File;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.metamodel.util.Action;
import org.apache.metamodel.util.ImmutableRef;
import org.apache.metamodel.util.LazyRef;
import org.apache.metamodel.util.MutableRef;
import org.apache.metamodel.util.Ref;
import org.datacleaner.bootstrap.DCWindowContext;
import org.datacleaner.bootstrap.WindowContext;
import org.datacleaner.configuration.DataCleanerConfiguration;
import org.datacleaner.configuration.DataCleanerConfigurationImpl;
import org.datacleaner.configuration.DataCleanerEnvironment;
import org.datacleaner.configuration.DataCleanerEnvironmentImpl;
import org.datacleaner.configuration.DataCleanerHomeFolder;
import org.datacleaner.configuration.DatastoreXmlExternalizer;
import org.datacleaner.configuration.InjectionManager;
import org.datacleaner.configuration.InjectionManagerFactory;
import org.datacleaner.connection.DatastoreCatalog;
import org.datacleaner.descriptors.ConfiguredPropertyDescriptor;
import org.datacleaner.descriptors.DescriptorProvider;
import org.datacleaner.descriptors.PropertyDescriptor;
import org.datacleaner.extensions.ExtensionPackage;
import org.datacleaner.extensions.ExtensionReader;
import org.datacleaner.job.AnalysisJob;
import org.datacleaner.job.builder.AnalysisJobBuilder;
import org.datacleaner.job.builder.ComponentBuilder;
import org.datacleaner.job.concurrent.TaskRunner;
import org.datacleaner.lifecycle.LifeCycleHelper;
import org.datacleaner.reference.ReferenceDataCatalog;
import org.datacleaner.result.AnalysisResult;
import org.datacleaner.result.renderer.RendererFactory;
import org.datacleaner.storage.StorageProvider;
import org.datacleaner.user.DataCleanerConfigurationReader;
import org.datacleaner.user.DataCleanerHome;
import org.datacleaner.user.MutableDatastoreCatalog;
import org.datacleaner.user.MutableReferenceDataCatalog;
import org.datacleaner.user.UsageLogger;
import org.datacleaner.user.UserPreferences;
import org.datacleaner.user.UserPreferencesImpl;
import org.datacleaner.util.SystemProperties;
import org.datacleaner.util.VFSUtils;
import org.datacleaner.util.VfsResource;
import org.datacleaner.util.convert.ClasspathResourceTypeHandler;
import org.datacleaner.util.convert.DummyRepositoryResourceFileTypeHandler;
import org.datacleaner.util.convert.FileResourceTypeHandler;
import org.datacleaner.util.convert.HdfsResourceTypeHandler;
import org.datacleaner.util.convert.ResourceConverter;
import org.datacleaner.util.convert.ResourceConverter.ResourceTypeHandler;
import org.datacleaner.util.convert.UrlResourceTypeHandler;
import org.datacleaner.util.convert.VfsResourceTypeHandler;
import org.datacleaner.windows.AnalysisJobBuilderWindow;
import org.datacleaner.windows.AnalysisJobBuilderWindowImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.util.Modules;

/**
 * Google Guice module for DataCleaner. Defines the main contextual components
 * of a DataCleaner session.
 */
public class DCModuleImpl extends AbstractModule implements DCModule {

    private static final Logger logger = LoggerFactory.getLogger(DCModuleImpl.class);

    private final DataCleanerConfigurationReader _undecoratedConfigurationRef;
    private final Ref<UserPreferences> _userPreferencesRef;
    private final Ref<AnalysisJobBuilder> _analysisJobBuilderRef;
    private DataCleanerConfiguration _configuration;
    private WindowContext _windowContext;

    /**
     * Creates a DCModule based on a parent module. This constructor is
     * convenient when you want to create a module with overridden getter
     * methods.
     * 
     * @param parent
     * @param analysisJobBuilder
     *            the AnalysisJobBuilder to use within this module, or null if a
     *            new AnalysisJobBuilder should be created.
     */
    public DCModuleImpl(DCModule parent, final AnalysisJobBuilder analysisJobBuilder) {
        final DCModuleImpl p = (DCModuleImpl) parent;
        _undecoratedConfigurationRef = p._undecoratedConfigurationRef;
        _userPreferencesRef = p._userPreferencesRef;
        _configuration = p._configuration;
        _windowContext = p._windowContext;
        if (analysisJobBuilder == null) {
            _analysisJobBuilderRef = new MutableRef<AnalysisJobBuilder>();
        } else {
            _analysisJobBuilderRef = ImmutableRef.of(analysisJobBuilder);
        }
    }

    public DCModuleImpl() {
        this(defaultDataCleanerHome());
    }

    private static FileObject defaultDataCleanerHome() {
        try {
            return VFSUtils.getFileSystemManager().resolveFile(".");
        } catch (FileSystemException e) {
            throw new IllegalStateException(e);
        }
    }

    public DCModuleImpl(final FileObject dataCleanerHome) {
        this(dataCleanerHome, null);
    }

    /**
     * Constructs a new DCModule based only on a DataCleaner home directory. New
     * window contexts and analysis job builder will be created. Thus this
     * constructor should only be used to create a completely new environment
     * (at bootstrap time).
     * 
     * @param dataCleanerHome
     * @param configurationFile
     *            a configuration file override, or null if not requested
     */
    public DCModuleImpl(final FileObject dataCleanerHome, FileObject configurationFile) {
        _userPreferencesRef = createUserPreferencesRef(dataCleanerHome);
        _undecoratedConfigurationRef = new DataCleanerConfigurationReader(dataCleanerHome, configurationFile,
                _userPreferencesRef);
        _analysisJobBuilderRef = new MutableRef<AnalysisJobBuilder>();
        _configuration = null;
        _windowContext = null;
    }

    private final Ref<UserPreferences> createUserPreferencesRef(final FileObject dataCleanerHome) {
        try {
            if ("true".equalsIgnoreCase(System.getProperty(SystemProperties.SANDBOX))) {
                return new ImmutableRef<UserPreferences>(new UserPreferencesImpl(null));
            }
            if (dataCleanerHome == null || !dataCleanerHome.exists()) {
                logger.info(
                        "DataCleaner home was not set or does not exist. Non-persistent user preferences will be applied.");
                return new ImmutableRef<UserPreferences>(new UserPreferencesImpl(null));
            }

            final FileObject userPreferencesFile = dataCleanerHome
                    .resolveFile(UserPreferencesImpl.DEFAULT_FILENAME);

            return new LazyRef<UserPreferences>() {
                @Override
                protected UserPreferences fetch() {
                    return UserPreferencesImpl.load(userPreferencesFile, true);
                }
            };
        } catch (FileSystemException e) {
            throw new IllegalStateException("Not able to resolve files in DataCleaner home: " + dataCleanerHome, e);
        }
    }

    @Override
    protected void configure() {
        bind(AnalysisJobBuilderWindow.class).to(AnalysisJobBuilderWindowImpl.class);
        bind(InjectionManagerFactory.class).to(GuiceInjectionManagerFactory.class);
        bind(DCModule.class).toInstance(this);
    }

    @Provides
    public final WindowContext getWindowContext(DataCleanerConfiguration configuration,
            UserPreferences userPreferences, UsageLogger usageLogger) {
        if (_windowContext == null) {
            synchronized (DCModuleImpl.class) {
                if (_windowContext == null) {
                    _windowContext = new DCWindowContext(configuration, userPreferences, usageLogger);
                }
            }
        }
        return _windowContext;
    }

    @Provides
    public final DataCleanerEnvironment getDataCleanerEnvironment(DataCleanerConfiguration conf) {
        return conf.getEnvironment();
    }

    @Provides
    public final TaskRunner getTaskRunner(DataCleanerEnvironment environment) {
        return environment.getTaskRunner();
    }

    @Provides
    public final DescriptorProvider getDescriptorProvider(DataCleanerEnvironment environment) {
        return environment.getDescriptorProvider();
    }

    @Provides
    public final ReferenceDataCatalog getReferenceDataCatalog(DataCleanerConfiguration conf) {
        return conf.getReferenceDataCatalog();
    }

    @Provides
    public final InjectionManager getInjectionManager(InjectionManagerFactory injectionManagerFactory,
            DataCleanerConfiguration configuration, @Nullable AnalysisJob job) {
        return injectionManagerFactory.getInjectionManager(configuration, job);
    }

    @Provides
    public final LifeCycleHelper getLifeCycleHelper(InjectionManager injectionManager) {
        return new LifeCycleHelper(injectionManager, true);
    }

    @Provides
    public final DatastoreCatalog getDatastoreCatalog(DataCleanerConfiguration conf) {
        return conf.getDatastoreCatalog();
    }

    @Provides
    public final MutableReferenceDataCatalog getMutableReferenceDataCatalog(
            ReferenceDataCatalog referenceDataCatalog) {
        return (MutableReferenceDataCatalog) referenceDataCatalog;
    }

    @Provides
    public final MutableDatastoreCatalog getMutableDatastoreCatalog(DatastoreCatalog datastoreCatalog) {
        return (MutableDatastoreCatalog) datastoreCatalog;
    }

    @Provides
    @Undecorated
    public final DataCleanerConfiguration getUndecoratedAnalyzerBeansConfiguration() {
        return _undecoratedConfigurationRef.get();
    }

    @Deprecated
    @Provides
    public final org.datacleaner.configuration.AnalyzerBeansConfiguration getAnalyzerBeansConfiguration(
            @Undecorated DataCleanerConfiguration undecoratedConfiguration, UserPreferences userPreferences,
            InjectionManagerFactory injectionManagerFactory) {
        final DataCleanerConfiguration c = getDataCleanerConfiguration(undecoratedConfiguration, userPreferences,
                injectionManagerFactory);
        final DatastoreCatalog datastoreCatalog = c.getDatastoreCatalog();
        final ReferenceDataCatalog referenceDataCatalog = c.getReferenceDataCatalog();
        final DescriptorProvider descriptorProvider = c.getEnvironment().getDescriptorProvider();
        final TaskRunner taskRunner = c.getEnvironment().getTaskRunner();
        final StorageProvider storageProvider = c.getEnvironment().getStorageProvider();
        final DataCleanerHomeFolder homeFolder = c.getHomeFolder();
        return new org.datacleaner.configuration.AnalyzerBeansConfigurationImpl(datastoreCatalog,
                referenceDataCatalog, descriptorProvider, taskRunner, storageProvider, injectionManagerFactory,
                homeFolder);
    }

    @Provides
    public final DataCleanerConfiguration getDataCleanerConfiguration(@Undecorated DataCleanerConfiguration c,
            UserPreferences userPreferences, InjectionManagerFactory injectionManagerFactory) {
        if (_configuration == null) {
            synchronized (DCModuleImpl.class) {
                if (_configuration == null) {
                    // make the configuration mutable
                    final MutableDatastoreCatalog datastoreCatalog = new MutableDatastoreCatalog(
                            c.getDatastoreCatalog(), createDatastoreXmlExternalizer(), userPreferences);
                    final MutableReferenceDataCatalog referenceDataCatalog = new MutableReferenceDataCatalog(
                            c.getReferenceDataCatalog(), userPreferences,
                            new LifeCycleHelper(injectionManagerFactory.getInjectionManager(c, null), true));
                    final DescriptorProvider descriptorProvider = c.getEnvironment().getDescriptorProvider();

                    final ExtensionReader extensionReader = new ExtensionReader();
                    final List<ExtensionPackage> internalExtensions = extensionReader.getInternalExtensions();
                    for (ExtensionPackage extensionPackage : internalExtensions) {
                        extensionPackage.loadDescriptors(descriptorProvider);
                    }

                    final List<ExtensionPackage> extensionPackages = userPreferences.getExtensionPackages();
                    for (ExtensionPackage extensionPackage : extensionPackages) {
                        extensionPackage.loadDescriptors(descriptorProvider);
                    }

                    final StorageProvider storageProvider = c.getEnvironment().getStorageProvider();

                    final TaskRunner taskRunner = c.getEnvironment().getTaskRunner();
                    final DataCleanerEnvironment environment = new DataCleanerEnvironmentImpl(taskRunner,
                            descriptorProvider, storageProvider, injectionManagerFactory);

                    _configuration = new DataCleanerConfigurationImpl(environment,
                            DataCleanerHome.getAsDataCleanerHomeFolder(), datastoreCatalog, referenceDataCatalog);
                }
            }
        }

        if (_configuration instanceof DataCleanerConfigurationImpl) {
            final DataCleanerEnvironment environment = _configuration.getEnvironment();
            if (environment.getInjectionManagerFactory() != injectionManagerFactory) {
                // Ticket #905 and #925: Always replace the injection manager
                // factory to ensure correct scope when doing injections.
                final DataCleanerEnvironment replacementEnvironment = new DataCleanerEnvironmentImpl(environment)
                        .withInjectionManagerFactory(injectionManagerFactory);
                return ((DataCleanerConfigurationImpl) _configuration).withEnvironment(replacementEnvironment);
            }
        }

        return _configuration;
    }

    private DatastoreXmlExternalizer createDatastoreXmlExternalizer() {
        final FileObject configurationFile = _undecoratedConfigurationRef.getConfigurationFile();
        if (configurationFile == null) {
            return new DatastoreXmlExternalizer();
        }
        final VfsResource resource = new VfsResource(configurationFile);
        return new DatastoreXmlExternalizer(resource) {
            @Override
            protected void onDocumentChanged(final Document document) {
                resource.write(new Action<OutputStream>() {
                    @Override
                    public void run(final OutputStream out) throws Exception {
                        final Source source = new DOMSource(document);
                        final Result outputTarget = new StreamResult(out);
                        final TransformerFactory transformerFactory = TransformerFactory.newInstance();
                        final Transformer transformer = transformerFactory.newTransformer();
                        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
                        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
                        transformer.transform(source, outputTarget);
                    }
                });

            }
        };
    }

    @Provides
    public AnalysisJob getAnalysisJob(@Nullable AnalysisJobBuilder builder) {
        if (builder == null) {
            return null;
        }
        return builder.toAnalysisJob(false);
    }

    @Provides
    public final RendererFactory getRendererFactory(DataCleanerConfiguration configuration) {
        return new RendererFactory(configuration);
    }

    @Provides
    public AnalysisJobBuilder getAnalysisJobBuilder(DataCleanerConfiguration configuration) {
        AnalysisJobBuilder ajb = _analysisJobBuilderRef.get();
        if (ajb == null && _analysisJobBuilderRef instanceof MutableRef) {
            ajb = new AnalysisJobBuilder(configuration);
            MutableRef<AnalysisJobBuilder> ref = (MutableRef<AnalysisJobBuilder>) _analysisJobBuilderRef;
            ref.set(ajb);
        }
        return ajb;
    }

    @Provides
    @JobFile
    public FileObject getJobFilename() {
        return null;
    }

    @Provides
    public final DCModuleImpl getModule() {
        return this;
    }

    @Provides
    public AnalysisResult getAnalysisResult() {
        return null;
    }

    @Provides
    public final UserPreferences getUserPreferences() {
        return _userPreferencesRef.get();
    }

    @Provides
    public CloseableHttpClient getHttpClient(UserPreferences userPreferences) {
        return userPreferences.createHttpClient();
    }

    @Provides
    public ResourceConverter getResourceConverter() {
        final FileObject dataCleanerHome = DataCleanerHome.get();
        final File dataCleanerHomeDirectory = VFSUtils.toFile(dataCleanerHome);

        final List<ResourceTypeHandler<?>> handlers = new ArrayList<ResourceTypeHandler<?>>();
        handlers.add(new FileResourceTypeHandler(dataCleanerHomeDirectory));
        handlers.add(new UrlResourceTypeHandler());
        handlers.add(new ClasspathResourceTypeHandler());
        handlers.add(new VfsResourceTypeHandler());
        handlers.add(new HdfsResourceTypeHandler());
        handlers.add(new DummyRepositoryResourceFileTypeHandler());

        final ResourceConverter resourceConverter = new ResourceConverter(handlers,
                ResourceConverter.DEFAULT_DEFAULT_SCHEME);
        return resourceConverter;
    }

    @Override
    public InjectorBuilder createInjectorBuilder() {
        return new InjectorBuilder(this, Guice.createInjector(this));
    }

    @Override
    public Injector createChildInjectorForComponent(ComponentBuilder componentBuilder) {
        final ComponentBuilderModule componentBuilderModule = new ComponentBuilderModule(componentBuilder);
        final Module module = Modules.override(this).with(componentBuilderModule);
        return Guice.createInjector(module);
    }

    @Override
    public Injector createChildInjectorForProperty(ComponentBuilder componentBuilder,
            ConfiguredPropertyDescriptor propertyDescriptor) {
        final AdHocModule adHocModule = new AdHocModule();
        adHocModule.bind(PropertyDescriptor.class, propertyDescriptor);
        adHocModule.bind(ConfiguredPropertyDescriptor.class, propertyDescriptor);
        final ComponentBuilderModule componentBuilderModule = new ComponentBuilderModule(componentBuilder);
        final Module module = Modules.override(this).with(componentBuilderModule, adHocModule);
        return Guice.createInjector(module);
    }
}