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

org.datacleaner.configuration.DomConfigurationWriter 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.configuration;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.metamodel.csv.CsvConfiguration;
import org.apache.metamodel.schema.TableType;
import org.apache.metamodel.util.FileResource;
import org.apache.metamodel.util.HdfsResource;
import org.apache.metamodel.util.Resource;
import org.apache.metamodel.util.SimpleTableDef;
import org.apache.metamodel.xml.XmlDomDataContext;
import org.datacleaner.connection.CouchDbDatastore;
import org.datacleaner.connection.CsvDatastore;
import org.datacleaner.connection.Datastore;
import org.datacleaner.connection.DatastoreCatalog;
import org.datacleaner.connection.ElasticSearchDatastore;
import org.datacleaner.connection.ExcelDatastore;
import org.datacleaner.connection.FixedWidthDatastore;
import org.datacleaner.connection.JdbcDatastore;
import org.datacleaner.connection.JsonDatastore;
import org.datacleaner.connection.MongoDbDatastore;
import org.datacleaner.connection.SalesforceDatastore;
import org.datacleaner.reference.DatastoreDictionary;
import org.datacleaner.reference.DatastoreSynonymCatalog;
import org.datacleaner.reference.Dictionary;
import org.datacleaner.reference.RegexStringPattern;
import org.datacleaner.reference.SimpleDictionary;
import org.datacleaner.reference.SimpleStringPattern;
import org.datacleaner.reference.SimpleSynonymCatalog;
import org.datacleaner.reference.StringPattern;
import org.datacleaner.reference.SynonymCatalog;
import org.datacleaner.reference.TextFileDictionary;
import org.datacleaner.reference.TextFileSynonymCatalog;
import org.datacleaner.reference.regexswap.Category;
import org.datacleaner.reference.regexswap.Regex;
import org.datacleaner.reference.regexswap.RegexSwapStringPattern;
import org.datacleaner.server.DirectConnectionHadoopClusterInformation;
import org.datacleaner.server.DirectoryBasedHadoopClusterInformation;
import org.datacleaner.server.EnvironmentBasedHadoopClusterInformation;
import org.datacleaner.server.HadoopClusterInformation;
import org.datacleaner.util.HadoopResource;
import org.datacleaner.util.SecurityUtils;
import org.datacleaner.util.xml.XmlUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.google.common.base.Strings;

/**
 * Utility class for writing configuration elements to the XML format of conf.xml.
 *
 * Generally speaking, XML elements created by this class, and placed in a the <datastore-catalog> and
 * <reference-data-catalog> elements of conf.xml, will be readable by {@link JaxbConfigurationReader}.
 */
public class DomConfigurationWriter {

    private final Document _document;

    public DomConfigurationWriter() {
        _document = XmlUtils.createDocument();
    }

    public DomConfigurationWriter(final Resource resource) {
        _document = resource.read(is -> {
            return XmlUtils.parseDocument(is);
        });
    }

    public DomConfigurationWriter(final Document document) {
        _document = document;
    }

    /**
     * Determines if the given datastore is externalizable by this object.
     *
     * @param serverInformation
     * @return
     */
    public boolean isExternalizable(final ServerInformation serverInformation) {
        if (serverInformation == null) {
            return false;
        }

        if (serverInformation instanceof HadoopClusterInformation) {
            return true;
        }

        return false;
    }

    /**
     * Determines if the given datastore is externalizable by this object.
     *
     * @param datastore
     * @return
     */
    public boolean isExternalizable(final Datastore datastore) {
        if (datastore == null) {
            return false;
        }

        if (datastore instanceof JdbcDatastore) {
            return true;
        }

        if (datastore instanceof CsvDatastore) {
            final Resource resource = ((CsvDatastore) datastore).getResource();
            if (resource instanceof FileResource) {
                return true;
            }
            if (resource instanceof HdfsResource) {
                return true;
            }
        }

        if (datastore instanceof ExcelDatastore) {
            final Resource resource = ((ExcelDatastore) datastore).getResource();
            if (resource instanceof FileResource) {
                return true;
            }
        }

        if (datastore instanceof ElasticSearchDatastore) {
            final SimpleTableDef[] tableDefs = ((ElasticSearchDatastore) datastore).getTableDefs();
            if (tableDefs == null) {
                return true;
            }
        }

        if (datastore instanceof MongoDbDatastore) {
            final SimpleTableDef[] tableDefs = ((MongoDbDatastore) datastore).getTableDefs();
            if (tableDefs == null) {
                return true;
            }
        }

        if (datastore instanceof CouchDbDatastore) {
            final SimpleTableDef[] tableDefs = ((CouchDbDatastore) datastore).getTableDefs();
            if (tableDefs == null) {
                return true;
            }
        }

        if (datastore instanceof SalesforceDatastore) {
            return true;
        }

        if (datastore instanceof JsonDatastore) {
            return true;
        }
        if (datastore instanceof FixedWidthDatastore) {
            return true;
        }

        return false;
    }

    public boolean isExternalizable(final Dictionary dict) {
        return dict instanceof SimpleDictionary || dict instanceof TextFileDictionary
                || dict instanceof DatastoreDictionary;
    }

    public boolean isExternalizable(final SynonymCatalog sc) {
        return sc instanceof TextFileSynonymCatalog || sc instanceof DatastoreSynonymCatalog;
    }

    public boolean isExternalizable(final StringPattern sp) {
        return sp instanceof SimpleStringPattern || sp instanceof RegexStringPattern;
    }

    /**
     * Removes a Hadoop cluster by its name, if it exists and is recognizeable by the externalizer.
     *
     * @param serverName
     * @return true if a server information element was removed from the XML document.
     */
    public boolean removeHadoopClusterServerInformation(final String serverName) {
        final Element serverInformationCatalogElement = getServerInformationCatalogElement();
        final Element hadoopClustersElement =
                getOrCreateChildElementByTagName(serverInformationCatalogElement, "hadoop-clusters");
        return removeChildElementByNameAttribute(serverName, hadoopClustersElement);
    }

    /**
     * Removes a datastore by its name, if it exists and is recognizeable by the externalizer.
     *
     * @param datastoreName
     * @return true if a datastore element was removed from the XML document.
     */
    public boolean removeDatastore(final String datastoreName) {
        final Element datastoreCatalogElement = getDatastoreCatalogElement();
        return removeChildElementByNameAttribute(datastoreName, datastoreCatalogElement);
    }

    /**
     * Removes a dictionary by its name, if it exists and is recognizable by the externalizer.
     *
     * @param dictionaryName
     * @return true if dictionary element was removed from the XML document
     */
    public boolean removeDictionary(final String dictionaryName) {
        final Element dictionariesElement = getDictionariesElement();
        return removeChildElementByNameAttribute(dictionaryName, dictionariesElement);
    }

    /**
     * Removes a synonym catalog by its name, if it exists and is recognizable by the externalizer.
     *
     * @param synonymCatalogName
     * @return true if dictionary element was removed from the XML document
     */
    public boolean removeSynonymCatalog(final String synonymCatalogName) {
        final Element synonymCatalogsElement = getSynonymCatalogsElement();
        return removeChildElementByNameAttribute(synonymCatalogName, synonymCatalogsElement);
    }

    /**
     * Removes a string pattern by its name, if it exists and is recognizable by the externalizer.
     *
     * @param stringPatternName
     * @return true if string pattern element was removed from the XML document
     */
    public boolean removeStringPattern(final String stringPatternName) {
        final Element stringPatternsElement = getStringPatternsElement();
        return removeChildElementByNameAttribute(stringPatternName, stringPatternsElement);
    }

    private boolean removeChildElementByNameAttribute(final String dictionaryName, final Element dictionariesElement) {
        final NodeList childNodes = dictionariesElement.getChildNodes();
        final int length = childNodes.getLength();
        for (int i = 0; i < length; i++) {
            final Node node = childNodes.item(i);
            if (node instanceof Element) {
                final Element element = (Element) node;
                final Attr[] attributes = XmlDomDataContext.getAttributes(element);
                for (final Attr attr : attributes) {
                    if ("name".equals(attr.getName())) {
                        final String value = attr.getValue();
                        if (dictionaryName.equals(value)) {
                            // we have a match
                            dictionariesElement.removeChild(element);

                            onDocumentChanged(getDocument());

                            return true;
                        }
                    }
                }
            }
        }

        return false;
    }

    public Element externalize(final ServerInformation serverInformation) throws UnsupportedOperationException {
        if (serverInformation == null) {
            throw new IllegalArgumentException("ServerInformation cannot be null");
        }

        final Element elem;

        if (serverInformation instanceof HadoopClusterInformation) {
            elem = toElement((HadoopClusterInformation) serverInformation);
        } else {
            throw new UnsupportedOperationException("Non-supported serverInformation: " + serverInformation);
        }

        final Element serverInformationCatalogElement = getHadoopClustersElement();
        serverInformationCatalogElement.appendChild(elem);

        onDocumentChanged(getDocument());

        return elem;
    }

    /**
     * Externalizes the given datastore
     *
     * @param datastore
     * @return
     * @throws UnsupportedOperationException
     */
    public Element externalize(final Datastore datastore) throws UnsupportedOperationException {
        if (datastore == null) {
            throw new IllegalArgumentException("Datastore cannot be null");
        }

        final Element elem;

        if (datastore instanceof CsvDatastore) {
            final Resource resource = ((CsvDatastore) datastore).getResource();
            final String filename = toFilename(resource);
            elem = toElement((CsvDatastore) datastore, filename);
        } else if (datastore instanceof ExcelDatastore) {
            final Resource resource = ((ExcelDatastore) datastore).getResource();
            final String filename = toFilename(resource);
            elem = toElement((ExcelDatastore) datastore, filename);
        } else if (datastore instanceof JdbcDatastore) {
            elem = toElement((JdbcDatastore) datastore);
        } else if (datastore instanceof ElasticSearchDatastore) {
            elem = toElement((ElasticSearchDatastore) datastore);
        } else if (datastore instanceof MongoDbDatastore) {
            elem = toElement((MongoDbDatastore) datastore);
        } else if (datastore instanceof CouchDbDatastore) {
            elem = toElement((CouchDbDatastore) datastore);
        } else if (datastore instanceof SalesforceDatastore) {
            elem = toElement((SalesforceDatastore) datastore);
        } else if (datastore instanceof JsonDatastore) {
            final Resource resource = ((JsonDatastore) datastore).getResource();
            final String filename = toFilename(resource);
            elem = toElement((JsonDatastore) datastore, filename);
        } else if (datastore instanceof FixedWidthDatastore) {
            final Resource resource = ((FixedWidthDatastore) datastore).getResource();
            final String filename = toFilename(resource);
            elem = toElement((FixedWidthDatastore) datastore, filename);
        } else {
            throw new UnsupportedOperationException("Non-supported datastore: " + datastore);
        }

        final Element datastoreCatalogElement = getDatastoreCatalogElement();
        datastoreCatalogElement.appendChild(elem);

        onDocumentChanged(getDocument());

        return elem;
    }

    public Element externalize(final Dictionary dictionary) throws UnsupportedOperationException {
        if (dictionary == null) {
            throw new IllegalArgumentException("Dictionary cannot be null");
        }

        final Element elem;

        if (dictionary instanceof SimpleDictionary) {
            elem = toElement((SimpleDictionary) dictionary);
        } else if (dictionary instanceof TextFileDictionary) {
            elem = toElement((TextFileDictionary) dictionary);
        } else if (dictionary instanceof DatastoreDictionary) {
            elem = toElement((DatastoreDictionary) dictionary);
        } else {
            throw new UnsupportedOperationException("Non-supported dictionary: " + dictionary);
        }

        final Element dictionariesElement = getDictionariesElement();
        dictionariesElement.appendChild(elem);

        onDocumentChanged(getDocument());

        return elem;
    }

    public Element externalize(final SynonymCatalog sc) throws UnsupportedOperationException {
        if (sc == null) {
            throw new IllegalArgumentException("SynonymCatalog cannot be null");
        }

        final Element elem;

        if (sc instanceof TextFileSynonymCatalog) {
            elem = toElement((TextFileSynonymCatalog) sc);
        } else if (sc instanceof DatastoreSynonymCatalog) {
            elem = toElement((DatastoreSynonymCatalog) sc);
        } else if (sc instanceof SimpleSynonymCatalog) {
            elem = toElement((SimpleSynonymCatalog) sc);
        } else {
            throw new UnsupportedOperationException("Non-supported synonym catalog: " + sc);
        }

        final Element synonymCatalogsElement = getSynonymCatalogsElement();
        synonymCatalogsElement.appendChild(elem);

        onDocumentChanged(getDocument());

        return elem;
    }

    public Element externalize(final StringPattern sp) throws UnsupportedOperationException {
        if (sp == null) {
            throw new IllegalArgumentException("StringPattern cannot be null");
        }

        final Element elem;

        if (sp instanceof SimpleStringPattern) {
            elem = toElement((SimpleStringPattern) sp);
        } else if (sp instanceof RegexStringPattern) {
            elem = toElement((RegexStringPattern) sp);
        } else if (sp instanceof RegexSwapStringPattern) {
            elem = toElement((RegexSwapStringPattern) sp);
        } else {
            throw new UnsupportedOperationException("Non-supported string pattern: " + sp);
        }

        final Element stringPatternsElement = getStringPatternsElement();
        stringPatternsElement.appendChild(elem);

        onDocumentChanged(getDocument());

        return elem;
    }

    private Element toElement(final RegexStringPattern sp) {
        final Element elem = getDocument().createElement("regex-pattern");
        elem.setAttribute("name", sp.getName());
        if (!Strings.isNullOrEmpty(sp.getDescription())) {
            elem.setAttribute("description", sp.getDescription());
        }

        appendElement(elem, "expression", sp.getExpression());
        appendElement(elem, "match-entire-string", sp.isMatchEntireString());

        return elem;
    }

    private Element toElement(final RegexSwapStringPattern regexSwapStringPattern) {
        final Element patternElement = getDocument().createElement("regex-swap-pattern");
        final Regex regex = regexSwapStringPattern.getRegex();
        patternElement.setAttribute("name", regex.getName());
        patternElement.setAttribute("description", regex.getDescription());
        appendElement(patternElement, "expression", regex.getExpression());
        appendElement(patternElement, "author", regex.getAuthor());
        appendElement(patternElement, "detailsUrl", regex.getDetailsUrl());
        appendElement(patternElement, "negativeVotes", regex.getNegativeVotes());
        appendElement(patternElement, "positiveVotes", regex.getPositiveVotes());
        appendElement(patternElement, "timestamp", regex.getTimestamp());
        appendElement(patternElement, "categories", getCSVCategoryList(regex.getCategories()));

        return patternElement;
    }

    private String getCSVCategoryList(final List categories) {
        if (categories == null || categories.size() <= 0) {
            return "";
        }

        final StringBuilder builder = new StringBuilder();

        for (final Category category : categories) {
            builder.append(category.getName()).append(",");
        }

        final String csvList = builder.toString();

        return csvList.substring(0, csvList.length() - 1); // remove last comma
    }

    private Element toElement(final SimpleStringPattern sp) {
        final Element elem = getDocument().createElement("simple-pattern");
        elem.setAttribute("name", sp.getName());
        if (!Strings.isNullOrEmpty(sp.getDescription())) {
            elem.setAttribute("description", sp.getDescription());
        }

        appendElement(elem, "expression", sp.getExpression());

        return elem;
    }

    private Element toElement(final DatastoreSynonymCatalog sc) {
        final Element elem = getDocument().createElement("datastore-synonym-catalog");
        elem.setAttribute("name", sc.getName());
        if (!Strings.isNullOrEmpty(sc.getDescription())) {
            elem.setAttribute("description", sc.getDescription());
        }

        appendElement(elem, "datastore-name", sc.getDatastoreName());
        appendElement(elem, "master-term-column-path", sc.getMasterTermColumnPath());

        final String[] synonymColumnPaths = sc.getSynonymColumnPaths();
        for (final String path : synonymColumnPaths) {
            appendElement(elem, "synonym-column-path", path);
        }

        appendElement(elem, "load-into-memory", sc.isLoadIntoMemory());

        return elem;
    }

    private Element toElement(final TextFileSynonymCatalog sc) {
        final Element elem = getDocument().createElement("text-file-synonym-catalog");
        elem.setAttribute("name", sc.getName());
        if (!Strings.isNullOrEmpty(sc.getDescription())) {
            elem.setAttribute("description", sc.getDescription());
        }

        appendElement(elem, "filename", sc.getFilename());
        appendElement(elem, "encoding", sc.getEncoding());
        appendElement(elem, "case-sensitive", sc.isCaseSensitive());

        return elem;
    }

    private Element toElement(final SimpleSynonymCatalog synonymCatalog) {
        final Element elem = getDocument().createElement("simple-synonym-catalog");
        elem.setAttribute("name", synonymCatalog.getName());
        if (!Strings.isNullOrEmpty(synonymCatalog.getDescription())) {
            elem.setAttribute("description", synonymCatalog.getDescription());
        }

        for (final Map.Entry entry : synonymCatalog.getSynonymMap().entrySet()) {
            final Element synonym = _document.createElement("synonym");
            appendElement(synonym, "masterterm", entry.getValue());
            // No, it's not a bug. The map is structured synonym to masterterm for performance.
            appendElement(synonym, "value", entry.getKey());
            elem.appendChild(synonym);
        }

        return elem;
    }

    private Element toElement(final SimpleDictionary dictionary) {
        final Element elem = getDocument().createElement("value-list-dictionary");
        elem.setAttribute("name", dictionary.getName());
        if (!Strings.isNullOrEmpty(dictionary.getDescription())) {
            elem.setAttribute("description", dictionary.getDescription());
        }

        final Set values = dictionary.getValueSet();
        for (final String value : values) {
            appendElement(elem, "value", value);
        }

        appendElement(elem, "case-sensitive", dictionary.isCaseSensitive());

        return elem;
    }

    private Element toElement(final TextFileDictionary dictionary) {
        final Element elem = getDocument().createElement("text-file-dictionary");
        elem.setAttribute("name", dictionary.getName());
        if (!Strings.isNullOrEmpty(dictionary.getDescription())) {
            elem.setAttribute("description", dictionary.getDescription());
        }

        appendElement(elem, "filename", dictionary.getFilename());
        appendElement(elem, "encoding", dictionary.getEncoding());
        appendElement(elem, "case-sensitive", dictionary.isCaseSensitive());

        return elem;
    }

    private Element toElement(final DatastoreDictionary dictionary) {
        final Element elem = getDocument().createElement("datastore-dictionary");
        elem.setAttribute("name", dictionary.getName());
        if (!Strings.isNullOrEmpty(dictionary.getDescription())) {
            elem.setAttribute("description", dictionary.getDescription());
        }

        appendElement(elem, "datastore-name", dictionary.getDatastoreName());
        appendElement(elem, "column-path", dictionary.getQualifiedColumnName());
        appendElement(elem, "load-into-memory", dictionary.isLoadIntoMemory());

        return elem;
    }

    /**
     * Overrideable method, invoked whenever the document has changed
     *
     * @param document
     */
    protected void onDocumentChanged(final Document document) {
    }

    /**
     * Creates a filename string to externalize, based on a given {@link Resource}.
     *
     * @param resource
     * @return
     * @throws UnsupportedOperationException
     */
    protected String toFilename(final Resource resource) throws UnsupportedOperationException {
        if (resource instanceof FileResource) {
            return ((FileResource) resource).getFile().getPath();
        }
        if (resource instanceof HadoopResource) {
            return ((HadoopResource) resource).getTemplatedPath();
        }
        if (resource instanceof HdfsResource) {
            return resource.getQualifiedPath();
        }

        throw new UnsupportedOperationException("Unsupported resource type: " + resource);
    }

    /**
     * Externalizes a {@link JdbcDatastore} to a XML element.
     *
     * @param datastore
     * @return
     */
    public Element toElement(final JdbcDatastore datastore) {
        final Element ds = getDocument().createElement("jdbc-datastore");
        ds.setAttribute("name", datastore.getName());
        if (!Strings.isNullOrEmpty(datastore.getDescription())) {
            ds.setAttribute("description", datastore.getDescription());
        }

        final String jndiUrl = datastore.getDatasourceJndiUrl();
        if (Strings.isNullOrEmpty(jndiUrl)) {
            appendElement(ds, "url", datastore.getJdbcUrl());
            appendElement(ds, "driver", datastore.getDriverClass());
            appendElement(ds, "username", datastore.getUsername());
            appendElement(ds, "password", encodePassword(datastore.getPassword()));
            appendElement(ds, "multiple-connections", datastore.isMultipleConnections() + "");
        } else {
            appendElement(ds, "datasource-jndi-url", jndiUrl);
        }

        final TableType[] tableTypes = datastore.getTableTypes();
        if (tableTypes != null && tableTypes.length != 0 && !Arrays.equals(TableType.DEFAULT_TABLE_TYPES, tableTypes)) {
            final Element tableTypesElement = getDocument().createElement("table-types");
            ds.appendChild(tableTypesElement);

            for (final TableType tableType : tableTypes) {
                appendElement(tableTypesElement, "table-type", tableType.name());
            }
        }

        final String catalogName = datastore.getCatalogName();
        if (!Strings.isNullOrEmpty(catalogName)) {
            appendElement(ds, "catalog-name", catalogName);
        }

        return ds;
    }

    private String encodePassword(final String password) {
        if (password == null) {
            return null;
        }

        return SecurityUtils.encodePasswordWithPrefix(password);
    }

    private String encodePassword(final char[] password) {
        return encodePassword(new String(password));
    }

    /**
     * Externalizes a {@link HadoopClusterInformation} to a XML element.
     *
     * @param hadoopClusterInformation the hadoopClusterInformation to externalize
     * @return a XML element representing the datastore.
     */
    public Element toElement(final HadoopClusterInformation hadoopClusterInformation) {
        final Element hadoopClusterElement = getDocument().createElement("hadoop-cluster");

        hadoopClusterElement.setAttribute("name", hadoopClusterInformation.getName());

        final String description = hadoopClusterInformation.getDescription();
        if (!Strings.isNullOrEmpty(description)) {
            hadoopClusterElement.setAttribute("description", description);
        }

        // These inherit each other, so order is important
        if (hadoopClusterInformation instanceof DirectConnectionHadoopClusterInformation) {
            appendElement(hadoopClusterElement, "namenode-url",
                    ((DirectConnectionHadoopClusterInformation) hadoopClusterInformation).getNameNodeUri().toString());
        } else if (hadoopClusterInformation instanceof EnvironmentBasedHadoopClusterInformation) {
            appendElement(hadoopClusterElement, "environment-configured", "");
        } else if (hadoopClusterInformation instanceof DirectoryBasedHadoopClusterInformation) {
            final DirectoryBasedHadoopClusterInformation directoryBasedHadoopClusterInformation =
                    (DirectoryBasedHadoopClusterInformation) hadoopClusterInformation;
            final Element directoriesElement = getDocument().createElement("directories");
            hadoopClusterElement.appendChild(directoriesElement);
            for (final String directory : directoryBasedHadoopClusterInformation.getDirectories()) {
                appendElement(directoriesElement, "directory", directory);
            }
        } else {
            throw new UnsupportedOperationException("Unknown Hadoop cluster configuration");
        }

        return hadoopClusterElement;
    }

    /**
     * Externalizes a {@link ElasticSearchDatastore} to a XML element
     *
     * @param datastore
     * @return
     */
    public Element toElement(final ElasticSearchDatastore datastore) {
        final Element ds = getDocument().createElement("elasticsearch-datastore");
        ds.setAttribute("name", datastore.getName());
        if (!Strings.isNullOrEmpty(datastore.getDescription())) {
            ds.setAttribute("description", datastore.getDescription());
        }

        appendElement(ds, "hostname", datastore.getHostname());
        appendElement(ds, "port", datastore.getPort());
        appendElement(ds, "cluster-name", datastore.getClusterName());
        appendElement(ds, "index-name", datastore.getIndexName());
        appendElement(ds, "client-type", datastore.getClientType().name());
        appendElement(ds, "username", datastore.getUsername());
        appendElement(ds, "password", encodePassword(datastore.getPassword()));
        appendElement(ds, "ssl", datastore.getSsl());

        if (datastore.getSsl()) {
            appendElement(ds, "keystore-path", datastore.getKeystorePath());
            appendElement(ds, "keystore-password", encodePassword(datastore.getKeystorePassword()));
        }

        return ds;
    }

    /**
     * Externalizes a {@link MongoDbDatastore} to a XML element
     *
     * @param datastore
     * @return
     */
    public Element toElement(final MongoDbDatastore datastore) {
        final Element ds = getDocument().createElement("mongodb-datastore");
        ds.setAttribute("name", datastore.getName());
        if (!Strings.isNullOrEmpty(datastore.getDescription())) {
            ds.setAttribute("description", datastore.getDescription());
        }

        appendElement(ds, "hostname", datastore.getHostname());
        appendElement(ds, "port", datastore.getPort());
        appendElement(ds, "database-name", datastore.getDatabaseName());
        appendElement(ds, "username", datastore.getUsername());
        appendElement(ds, "password", encodePassword(datastore.getPassword()));

        return ds;
    }

    /**
     * Externalizes a {@link CouchDbDatastore} to a XML element
     *
     * @param datastore
     * @return
     */
    public Element toElement(final CouchDbDatastore datastore) {
        final Element ds = getDocument().createElement("couchdb-datastore");
        ds.setAttribute("name", datastore.getName());
        if (!Strings.isNullOrEmpty(datastore.getDescription())) {
            ds.setAttribute("description", datastore.getDescription());
        }

        appendElement(ds, "hostname", datastore.getHostname());
        appendElement(ds, "port", datastore.getPort());
        appendElement(ds, "username", datastore.getUsername());
        appendElement(ds, "password", encodePassword(datastore.getPassword()));
        appendElement(ds, "ssl", datastore.isSslEnabled());

        return ds;
    }

    public Element toElement(final FixedWidthDatastore datastore, final String filename) {
        final Element ds = getDocument().createElement("fixed-width-datastore");
        ds.setAttribute("name", datastore.getName());
        if (!Strings.isNullOrEmpty(datastore.getDescription())) {
            ds.setAttribute("description", datastore.getDescription());
        }
        appendElement(ds, "filename", filename);
        appendElement(ds, "encoding", datastore.getEncoding());

        final Element widthElement = getDocument().createElement("width-specification");
        final int fixedValueWidth = datastore.getFixedValueWidth();
        if (fixedValueWidth > -1) {
            final String valueOf = String.valueOf(fixedValueWidth);
            appendElement(widthElement, "fixed-value-width", valueOf);
        } else {
            final int[] valueWidths = datastore.getValueWidths();
            for (int i = 0; i < valueWidths.length; i++) {
                appendElement(widthElement, "value-width", String.valueOf(valueWidths[i]));
            }
        }
        ds.appendChild(widthElement);

        final List customColumnNames = datastore.getCustomColumnNames();
        if (customColumnNames != null && !customColumnNames.isEmpty()) {
            final Element columnNamesElement = getDocument().createElement("custom-column-names");
            for (String columnName : customColumnNames) {
                appendElement(widthElement, "column-name", columnName);
            }
            ds.appendChild(columnNamesElement);
        }

        appendElement(ds, "header-line-number", datastore.getHeaderLineNumber());
        appendElement(ds, "fail-on-inconsistencies", String.valueOf(datastore.isFailOnInconsistencies()));
        appendElement(ds, "skip-ebcdic-header", String.valueOf(datastore.isSkipEbcdicHeader()));
        appendElement(ds, "eol-present", String.valueOf(datastore.isEolPresent()));

        return ds;
    }

    /**
     * Externalizes a {@link CouchDbDatastore} to an XML element
     *
     * @param datastore
     * @return
     */
    public Element toElement(final SalesforceDatastore datastore) {
        final Element ds = getDocument().createElement("salesforce-datastore");
        ds.setAttribute("name", datastore.getName());
        if (!Strings.isNullOrEmpty(datastore.getDescription())) {
            ds.setAttribute("description", datastore.getDescription());
        }

        appendElement(ds, "username", datastore.getUsername());
        appendElement(ds, "password", encodePassword(datastore.getPassword()));
        appendElement(ds, "security-token", datastore.getSecurityToken());

        final String endpointUrl = datastore.getEndpointUrl();
        if (!Strings.isNullOrEmpty(endpointUrl)) {
            appendElement(ds, "endpoint-url", endpointUrl);
        }

        return ds;
    }

    /**
     * Externalizes a {@link ExcelDatastore} to a XML element.
     *
     * @param datastore
     * @param filename the filename/path to use in the XML element. Since the appropriate path will depend on the
     *            reading application's environment (supported {@link Resource} types), this specific property of the
     *            datastore is provided separately.
     * @return
     */
    public Element toElement(final ExcelDatastore datastore, final String filename) {
        final Element ds = getDocument().createElement("excel-datastore");

        ds.setAttribute("name", datastore.getName());
        if (!Strings.isNullOrEmpty(datastore.getDescription())) {
            ds.setAttribute("description", datastore.getDescription());
        }

        appendElement(ds, "filename", filename);

        if (datastore.getCustomColumnNames() != null && datastore.getCustomColumnNames().size() > 0) {
            final Element customColumnNamesElement = getDocument().createElement("custom-column-names");
            ds.appendChild(customColumnNamesElement);

            datastore.getCustomColumnNames()
                    .forEach(columnName -> appendElement(customColumnNamesElement, "column-name", columnName));
        }

        return ds;
    }

    /**
     * Externalizes a {@link CsvDatastore} to a XML element.
     *
     * @param datastore the datastore to externalize
     * @param filename the filename/path to use in the XML element. Since the appropriate path will depend on the
     *            reading application's environment (supported {@link Resource} types), this specific property of the
     *            datastore is provided separately.
     * @return a XML element representing the datastore.
     */
    public Element toElement(final CsvDatastore datastore, final String filename) {
        final Element datastoreElement = getDocument().createElement("csv-datastore");
        datastoreElement.setAttribute("name", datastore.getName());

        final String description = datastore.getDescription();
        if (!Strings.isNullOrEmpty(description)) {
            datastoreElement.setAttribute("description", description);
        }

        appendElement(datastoreElement, "filename", filename);
        appendElement(datastoreElement, "quote-char", datastore.getQuoteChar());
        appendElement(datastoreElement, "separator-char", datastore.getSeparatorChar());
        appendElement(datastoreElement, "escape-char", datastore.getEscapeChar());
        appendElement(datastoreElement, "encoding", datastore.getEncoding());
        appendElement(datastoreElement, "fail-on-inconsistencies", datastore.isFailOnInconsistencies());
        appendElement(datastoreElement, "multiline-values", datastore.isMultilineValues());
        appendElement(datastoreElement, "header-line-number", datastore.getHeaderLineNumber());

        if (datastore.getCustomColumnNames() != null && datastore.getCustomColumnNames().size() > 0) {
            final Element customColumnNamesElement = getDocument().createElement("custom-column-names");
            datastoreElement.appendChild(customColumnNamesElement);

            datastore.getCustomColumnNames()
                    .forEach(columnName -> appendElement(customColumnNamesElement, "column-name", columnName));
        }

        return datastoreElement;
    }

    /**
     * Extrnalizes a Json datastore
     * 
     * @param datastore
     * @param filename
     * @return
     */
    public Element toElement(final JsonDatastore datastore, final String filename) {
        final Element datastoreElement = getDocument().createElement("json-datastore");
        datastoreElement.setAttribute("name", datastore.getName());
        final String description = datastore.getDescription();
        if (!Strings.isNullOrEmpty(description)) {
            datastoreElement.setAttribute("description", description);
        }
        appendElement(datastoreElement, "filename", filename);

        return datastoreElement;
    }

    /**
     * Gets the XML document that has been built.
     *
     * @return
     */
    public final Document getDocument() {
        return _document;
    }

    /**
     * Gets the XML element that represents the {@link DatastoreCatalog}.
     *
     * @return
     */
    public Element getDatastoreCatalogElement() {
        final Element configurationFileDocumentElement = getDocumentElement();

        final Element datastoreCatalogElement =
                getOrCreateChildElementByTagName(configurationFileDocumentElement, "datastore-catalog");
        if (datastoreCatalogElement == null) {
            throw new IllegalStateException("Could not find  element in configuration file");
        }
        return datastoreCatalogElement;
    }

    /**
     * Get the XML element that represents the {@link ServerInformationCatalog}.
     */
    public Element getServerInformationCatalogElement() {
        final Element configurationFileDocumentElement = getDocumentElement();
        return getOrCreateChildElementByTagName(configurationFileDocumentElement, "servers");
    }

    /**
     * Get the XML element that represents the hadoop cluster subset of {@link ServerInformationCatalog}.
     */
    public Element getHadoopClustersElement() {
        final Element hadoopClustersElement = getServerInformationCatalogElement();

        return getOrCreateChildElementByTagName(hadoopClustersElement, "hadoop-clusters");
    }

    /**
     * Gets the XML element that represents the dictionaries
     *
     * @return
     */
    public Element getDictionariesElement() {
        final Element referenceDataCatalogElement = getReferenceDataCatalogElement();

        final Element dictionariesElement =
                getOrCreateChildElementByTagName(referenceDataCatalogElement, "dictionaries");
        if (dictionariesElement == null) {
            throw new IllegalStateException("Could not find  element in configuration file");
        }
        return dictionariesElement;
    }

    /**
     * Gets the XML element that represents the synonym catalogs
     *
     * @return
     */
    public Element getSynonymCatalogsElement() {
        final Element referenceDataCatalogElement = getReferenceDataCatalogElement();

        final Element synonymCatalogsElement =
                getOrCreateChildElementByTagName(referenceDataCatalogElement, "synonym-catalogs");
        if (synonymCatalogsElement == null) {
            throw new IllegalStateException("Could not find  element in configuration file");
        }
        return synonymCatalogsElement;
    }

    /**
     * Gets the XML element that represents the string patterns
     *
     * @return
     */
    public Element getStringPatternsElement() {
        final Element referenceDataCatalogElement = getReferenceDataCatalogElement();

        final Element stringPatternsElement =
                getOrCreateChildElementByTagName(referenceDataCatalogElement, "string-patterns");
        if (stringPatternsElement == null) {
            throw new IllegalStateException("Could not find  element in configuration file");
        }
        return stringPatternsElement;
    }

    private Element getReferenceDataCatalogElement() {
        final Element configurationFileDocumentElement = getDocumentElement();

        final Element referenceDataCatalogElement =
                getOrCreateChildElementByTagName(configurationFileDocumentElement, "reference-data-catalog");
        if (referenceDataCatalogElement == null) {
            throw new IllegalStateException("Could not find  element in configuration file");
        }
        return referenceDataCatalogElement;
    }

    private Element getDocumentElement() {
        final Document document = getDocument();
        Element documentElement = document.getDocumentElement();
        if (documentElement == null) {
            documentElement = document.createElement("configuration");
            documentElement.setAttribute("xmlns", "http://eobjects.org/analyzerbeans/configuration/1.0");
            document.appendChild(documentElement);
        }
        return documentElement;
    }

    private Element getOrCreateChildElementByTagName(final Element element, final String tagName) {
        Element elem = getChildElementByTagName(element, tagName);
        if (elem == null) {
            elem = getDocument().createElement(tagName);
            element.appendChild(elem);
        }
        return elem;
    }

    private Element getChildElementByTagName(final Element element, final String tagName) {
        final NodeList nodeList = element.getElementsByTagName(tagName);
        if (nodeList == null) {
            return null;
        }
        final int length = nodeList.getLength();
        for (int i = 0; i < length; i++) {
            final Node node = nodeList.item(i);
            if (node instanceof Element) {
                return (Element) node;
            }
        }
        return null;
    }

    private void appendElement(final Element parent, final String elementName, Object value) {
        if (value == null) {
            return;
        }

        if (value instanceof char[]) {
            value = new String((char[]) value);
        }

        String stringValue = value.toString();

        if (value instanceof Character) {
            final char c = ((Character) value).charValue();
            if (c == CsvConfiguration.NOT_A_CHAR) {
                stringValue = "NOT_A_CHAR";
            } else if (c == '\t') {
                stringValue = "\\t";
            } else if (c == '\n') {
                stringValue = "\\n";
            } else if (c == '\r') {
                stringValue = "\\r";
            }
        }

        final Element element = getDocument().createElement(elementName);
        element.setTextContent(stringValue);
        parent.appendChild(element);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy