org.eobjects.datacleaner.guice.DCModule.java Source code

Java tutorial

Introduction

Here is the source code for org.eobjects.datacleaner.guice.DCModule.java

Source

/**
 * DataCleaner (community edition)
 * Copyright (C) 2013 Human Inference
 *
 * 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.eobjects.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.client.HttpClient;
import org.eobjects.analyzer.configuration.AnalyzerBeansConfiguration;
import org.eobjects.analyzer.configuration.AnalyzerBeansConfigurationImpl;
import org.eobjects.analyzer.configuration.DatastoreXmlExternalizer;
import org.eobjects.analyzer.configuration.InjectionManager;
import org.eobjects.analyzer.configuration.InjectionManagerFactory;
import org.eobjects.analyzer.connection.DatastoreCatalog;
import org.eobjects.analyzer.descriptors.DescriptorProvider;
import org.eobjects.analyzer.job.AnalysisJob;
import org.eobjects.analyzer.job.builder.AnalysisJobBuilder;
import org.eobjects.analyzer.job.concurrent.TaskRunner;
import org.eobjects.analyzer.job.runner.ReferenceDataActivationManager;
import org.eobjects.analyzer.lifecycle.LifeCycleHelper;
import org.eobjects.analyzer.reference.ReferenceDataCatalog;
import org.eobjects.analyzer.result.AnalysisResult;
import org.eobjects.analyzer.result.renderer.RendererFactory;
import org.eobjects.analyzer.storage.StorageProvider;
import org.eobjects.analyzer.util.VFSUtils;
import org.eobjects.analyzer.util.VfsResource;
import org.eobjects.analyzer.util.convert.ClasspathResourceTypeHandler;
import org.eobjects.analyzer.util.convert.FileResourceTypeHandler;
import org.eobjects.analyzer.util.convert.ResourceConverter;
import org.eobjects.analyzer.util.convert.ResourceConverter.ResourceTypeHandler;
import org.eobjects.analyzer.util.convert.UrlResourceTypeHandler;
import org.eobjects.analyzer.util.convert.VfsResourceTypeHandler;
import org.eobjects.datacleaner.bootstrap.DCWindowContext;
import org.eobjects.datacleaner.bootstrap.WindowContext;
import org.eobjects.datacleaner.extensions.ExtensionReader;
import org.eobjects.datacleaner.user.AuthenticationService;
import org.eobjects.datacleaner.user.DCAuthenticationService;
import org.eobjects.datacleaner.user.DataCleanerConfigurationReader;
import org.eobjects.datacleaner.user.DataCleanerHome;
import org.eobjects.datacleaner.user.DummyRepositoryResourceFileTypeHandler;
import org.eobjects.datacleaner.user.ExtensionPackage;
import org.eobjects.datacleaner.user.MutableDatastoreCatalog;
import org.eobjects.datacleaner.user.MutableReferenceDataCatalog;
import org.eobjects.datacleaner.user.UsageLogger;
import org.eobjects.datacleaner.user.UserPreferences;
import org.eobjects.datacleaner.user.UserPreferencesImpl;
import org.eobjects.datacleaner.util.SystemProperties;
import org.eobjects.datacleaner.windows.AnalysisJobBuilderWindow;
import org.eobjects.datacleaner.windows.AnalysisJobBuilderWindowImpl;
import org.eobjects.metamodel.util.Action;
import org.eobjects.metamodel.util.ImmutableRef;
import org.eobjects.metamodel.util.LazyRef;
import org.eobjects.metamodel.util.MutableRef;
import org.eobjects.metamodel.util.Ref;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;

import com.google.inject.AbstractModule;
import com.google.inject.Provides;

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

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

    private final DataCleanerConfigurationReader _undecoratedConfigurationRef;
    private final Ref<UserPreferences> _userPreferencesRef;
    private final Ref<AnalysisJobBuilder> _analysisJobBuilderRef;
    private AnalyzerBeansConfiguration _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 DCModule(DCModule parent, final AnalysisJobBuilder analysisJobBuilder) {
        _undecoratedConfigurationRef = parent._undecoratedConfigurationRef;
        _userPreferencesRef = parent._userPreferencesRef;
        _configuration = parent._configuration;
        _windowContext = parent._windowContext;
        if (analysisJobBuilder == null) {
            _analysisJobBuilderRef = new MutableRef<AnalysisJobBuilder>();
        } else {
            _analysisJobBuilderRef = ImmutableRef.of(analysisJobBuilder);
        }
    }

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

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

    public DCModule(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 DCModule(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("userpreferences.dat");

            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(AuthenticationService.class).to(DCAuthenticationService.class);
        bind(InjectionManagerFactory.class).to(GuiceInjectionManagerFactory.class);
    }

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

    @Provides
    public final TaskRunner getTaskRunner(AnalyzerBeansConfiguration conf) {
        return conf.getTaskRunner();
    }

    @Provides
    public final DescriptorProvider getDescriptorProvider(AnalyzerBeansConfiguration conf) {
        return conf.getDescriptorProvider();
    }

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

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

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

    @Provides
    public final DatastoreCatalog getDatastoreCatalog(AnalyzerBeansConfiguration 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 AnalyzerBeansConfiguration getUndecoratedAnalyzerBeansConfiguration() {
        return _undecoratedConfigurationRef.get();
    }

    @Provides
    public final AnalyzerBeansConfiguration getAnalyzerBeansConfiguration(@Undecorated AnalyzerBeansConfiguration c,
            UserPreferences userPreferences, InjectionManagerFactory injectionManagerFactory) {
        if (_configuration == null) {
            synchronized (DCModule.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), null, true));
                    final DescriptorProvider descriptorProvider = c.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.getStorageProvider();

                    _configuration = new AnalyzerBeansConfigurationImpl(datastoreCatalog, referenceDataCatalog,
                            descriptorProvider, c.getTaskRunner(), storageProvider, injectionManagerFactory);
                }
            }
        }

        if (_configuration instanceof AnalyzerBeansConfigurationImpl) {
            // Ticket #905 and #925: Always replace the injection manager
            // factory to ensure correct scope when doing injections.
            return ((AnalyzerBeansConfigurationImpl) _configuration).replace(injectionManagerFactory);
        }

        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(AnalyzerBeansConfiguration configuration) {
        return new RendererFactory(configuration);
    }

    @Provides
    public AnalysisJobBuilder getAnalysisJobBuilder(AnalyzerBeansConfiguration 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 DCModule getModule() {
        return this;
    }

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

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

    @Provides
    public HttpClient 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 DummyRepositoryResourceFileTypeHandler());

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