org.jumpmind.symmetric.io.FtpDataWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.jumpmind.symmetric.io.FtpDataWriter.java

Source

/**
 * Licensed to JumpMind Inc under one or more contributor
 * license agreements.  See the NOTICE file distributed
 * with this work for additional information regarding
 * copyright ownership.  JumpMind Inc licenses this file
 * to you under the GNU General Public License, version 3.0 (GPLv3)
 * (the "License"); you may not use this file except in compliance
 * with the License.
 *
 * You should have received a copy of the GNU General Public License,
 * version 3.0 (GPLv3) along with this library; if not, see
 * <http://www.gnu.org/licenses/>.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.jumpmind.symmetric.io;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileSystemOptions;
import org.apache.commons.vfs.Selectors;
import org.apache.commons.vfs.impl.StandardFileSystemManager;
import org.apache.commons.vfs.provider.ftp.FtpFileSystemConfigBuilder;
import org.apache.commons.vfs.provider.sftp.SftpFileSystemConfigBuilder;
import org.jumpmind.db.model.Table;
import org.jumpmind.exception.IoException;
import org.jumpmind.symmetric.io.data.Batch;
import org.jumpmind.symmetric.io.data.CsvData;
import org.jumpmind.symmetric.io.data.DataContext;
import org.jumpmind.symmetric.io.data.DataEventType;
import org.jumpmind.symmetric.io.data.IDataWriter;
import org.jumpmind.symmetric.io.data.writer.DataWriterStatisticConstants;
import org.jumpmind.util.Statistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FtpDataWriter implements IDataWriter {

    public enum Format {
        CSV
    }

    public enum Protocol {
        FTP, SFTP
    }

    protected static final Logger logger = LoggerFactory.getLogger(FtpDataWriter.class);

    protected String server;

    protected String username;

    protected String password;

    protected FtpDataWriter.Protocol protocol = Protocol.FTP;

    protected FtpDataWriter.Format format = Format.CSV;

    protected String stagingDir;

    protected String remoteDir;

    protected Batch batch;

    protected Table table;

    protected Map<String, FileInfo> fileInfoByTable = new HashMap<String, FtpDataWriter.FileInfo>();

    protected StandardFileSystemManager manager = new StandardFileSystemManager();

    protected Map<Batch, Statistics> statistics = new HashMap<Batch, Statistics>();

    public void setRemoteDir(String remoteDir) {
        this.remoteDir = remoteDir;
    }

    public void setFormat(FtpDataWriter.Format format) {
        this.format = format;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setServer(String server) {
        this.server = server;
    }

    public void setProtocol(FtpDataWriter.Protocol protocol) {
        this.protocol = protocol;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setStagingDir(String stagingDir) {
        this.stagingDir = stagingDir;
    }

    public void open(DataContext context) {
        try {
            manager.init();
        } catch (FileSystemException e) {
            throw new IoException(e);
        }
    }

    public void close() {
    }

    public Map<Batch, Statistics> getStatistics() {
        return statistics;
    }

    public void start(Batch batch) {
        this.batch = batch;
        this.statistics.put(batch, new Statistics());
    }

    public boolean start(Table table) {
        this.table = table;
        createFile(table, batch);
        return true;
    }

    public void write(CsvData data) {
        if (format == Format.CSV && (data.getDataEventType() == DataEventType.UPDATE
                || data.getDataEventType() == DataEventType.INSERT)) {
            printCsvData(data);
        }
    }

    public void end(Table table) {

    }

    public void end(Batch batch, boolean inError) {
        if (!inError) {
            try {
                closeFiles();
                sendFiles();
            } finally {
                deleteFiles();
            }
        } else {
            try {
                closeFiles();
            } finally {
                deleteFiles();
            }
        }
    }

    protected void createFile(Table table, Batch batch) {
        FileInfo fileInfo = fileInfoByTable.get(table.getFullyQualifiedTableName());
        if (fileInfo == null) {
            try {
                fileInfo = new FileInfo();
                fileInfo.outputFile = new File(stagingDir, batch.getBatchId() + "-"
                        + table.getFullyQualifiedTableName() + "." + format.name().toLowerCase());
                fileInfo.outputFile.getParentFile().mkdirs();
                fileInfo.outputFileWriter = new BufferedWriter(new FileWriter(fileInfo.outputFile));
                fileInfoByTable.put(table.getFullyQualifiedTableName(), fileInfo);
                if (format == Format.CSV) {
                    printCsvTableHeader();
                }
            } catch (IOException e) {
                throw new IoException(e);
            }
        }
    }

    protected void closeFiles() {
        Collection<FileInfo> fileInfos = fileInfoByTable.values();
        for (FileInfo fileInfo : fileInfos) {
            try {
                fileInfo.outputFileWriter.flush();
                fileInfo.outputFileWriter.close();
            } catch (IOException e) {
                logger.warn("", e);
            }
        }
    }

    protected void deleteFiles() {
        Collection<FileInfo> fileInfos = fileInfoByTable.values();
        for (FileInfo fileInfo : fileInfos) {
            try {
                fileInfo.outputFileWriter.close();
            } catch (IOException e) {
                logger.warn("", e);
            } finally {
                FileUtils.deleteQuietly(fileInfo.outputFile);
            }
        }

        fileInfoByTable.clear();
    }

    protected void sendFiles() {
        if (fileInfoByTable.size() > 0) {
            try {
                String sftpUri = buildUri();
                FileSystemOptions opts = new FileSystemOptions();
                FtpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
                SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(opts, "no");
                SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 60000);

                Collection<FileInfo> fileInfos = fileInfoByTable.values();
                for (FileInfo fileInfo : fileInfos) {
                    FileObject fileObject = manager.resolveFile(sftpUri + "/" + fileInfo.outputFile.getName(),
                            opts);
                    FileObject localFileObject = manager.resolveFile(fileInfo.outputFile.getAbsolutePath());
                    fileObject.copyFrom(localFileObject, Selectors.SELECT_SELF);
                    fileObject.close();
                }
            } catch (FileSystemException e) {
                logger.warn(
                        "If you have not configured your ftp connection it should be configured in conf/ftp-extensions.xml");
                throw new IoException(e);
            } catch (Exception e) {
                throw new IoException(e);
            } finally {
                manager.close();
            }
        }
    }

    protected String buildUri() {
        String credentials = "";
        if (StringUtils.isNotBlank(username)) {
            credentials = username;
            if (StringUtils.isNotBlank(password)) {
                credentials = credentials + ":" + password;
            }
            credentials = credentials + "@";
        }

        String path = "";
        if (StringUtils.isNotBlank(this.remoteDir)) {
            path = "/" + this.remoteDir;
        }

        return protocol.toString().toLowerCase() + "://" + credentials + server + path;
    }

    protected void printCsvTableHeader() {
        println(table.getColumnNames());
    }

    protected void printCsvData(CsvData data) {
        println(data.getParsedData(CsvData.ROW_DATA));
    }

    protected void println(String... data) {
        FileInfo fileInfo = fileInfoByTable.get(table.getFullyQualifiedTableName());
        if (fileInfo != null) {
            try {
                StringBuilder buffer = new StringBuilder();
                for (int i = 0; i < data.length; i++) {
                    if (i != 0) {
                        buffer.append(",");
                    }
                    buffer.append(data[i]);
                }
                buffer.append("\n");
                fileInfo.outputFileWriter.write(buffer.toString());
                long byteCount = buffer.length();
                statistics.get(batch).increment(DataWriterStatisticConstants.BYTECOUNT, byteCount);
            } catch (IOException e) {
                throw new IoException(e);
            }
        }
    }

    class FileInfo {
        File outputFile;
        BufferedWriter outputFileWriter;
    }

}