com.altoukhov.svsync.fileviews.SmbFileSpace.java Source code

Java tutorial

Introduction

Here is the source code for com.altoukhov.svsync.fileviews.SmbFileSpace.java

Source

/*
Copyright 2015 Alex Altoukhov
    
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    
http://www.apache.org/licenses/LICENSE-2.0
    
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 com.altoukhov.svsync.fileviews;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.regex.Pattern;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileFilter;
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import com.altoukhov.svsync.FileSnapshot;
import com.altoukhov.svsync.Snapshot;

/**
 * @author Alex Altoukhov
 */
public class SmbFileSpace extends FileSpace
        implements IScannableFileSpace, IReadableFileSpace, IWriteableFileSpace {

    private final NtlmPasswordAuthentication auth;
    private String rootPath;
    private String rootSuffix = "";

    private SmbFileSpace(String root, String domain, String user, String password) {

        if (domain == null)
            domain = "";
        if (user == null)
            user = "";
        if (password == null)
            password = "";
        auth = new NtlmPasswordAuthentication(domain, user, password);
        rootPath = root.endsWith("/") ? root : root + "/";
    }

    public SmbFileSpace(String root, String suffix, String domain, String user, String password) {
        this(root, domain, user, password);

        rootPath = rootPath + suffix;
        rootPath = rootPath.endsWith("/") ? rootPath : rootPath + "/";

        rootSuffix = suffix;
    }

    public SmbFileSpace(String root, List<String> excludes, String domain, String user, String password) {
        this(root, domain, user, password);

        for (String exclude : excludes) {
            this.excludes.add(toAbsoluteFilePath(exclude));
        }
    }

    public boolean init() {

        jcifs.Config.setProperty("jcifs.smb.client.responseTimeout", "60000");

        try {
            String rawRootPath = rootSuffix.isEmpty() ? rootPath
                    : rootPath.substring(0, rootPath.lastIndexOf(rootSuffix));

            SmbFile rawRoot = new SmbFile(rawRootPath, auth);

            if (rawRoot.exists() && rawRoot.isDirectory()) {

                SmbFile root = new SmbFile(rootPath, auth);
                if (!root.exists()) {
                    root.mkdirs();
                }

                return true;
            }
        } catch (MalformedURLException | SmbException ex) {
            System.out.println(ex.getMessage());
        }

        return false;
    }

    @Override
    protected Snapshot scan(List<Pattern> filters) {
        try {
            Map<String, FileSnapshot> files = new LinkedHashMap<>();
            Set<String> dirs = new HashSet<>();

            SmbFile root = new SmbFile(rootPath, auth);
            if (root.exists()) {

                Stack<SmbFile> stack = new Stack<>();
                stack.push(root);
                dirs.add("");

                while (!stack.isEmpty()) {
                    SmbFile currentFolder = stack.pop();

                    for (final SmbFile file : listFiles(currentFolder)) {

                        String path = file.getPath();

                        boolean isFile = isFile(file);
                        boolean isDirectory = isDirectory(file);

                        if (isFile && !isExcluded(path) && !isFiltered(toRelativePath(path), filters)) {
                            FileSnapshot fileSnapshot = createFileSnapshot(file, path);
                            files.put(fileSnapshot.getRelativePath(), fileSnapshot);
                        } else if (isDirectory && !isExcluded(path)
                                && !isFiltered(toRelativePath(path, true), filters)) {
                            stack.push(file);
                            dirs.add(toRelativePath(path));
                            System.out.println("Scanning " + path);
                        }
                    }
                }
            }
            Snapshot snapshot = new Snapshot(files, dirs);
            return snapshot;
        } catch (MalformedURLException | SmbException ex) {
            System.out.println("Failed to scan file space");
            System.out.println(ex.getMessage());
            System.out.println(ex);
        }

        return null;
    }

    @Override
    public InputStream readFile(String path) {

        try {
            SmbFile file = new SmbFile(toAbsoluteFilePath(path), auth);
            return file.getInputStream();
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
            return null;
        }
    }

    @Override
    public boolean createDirectory(String path) {

        try {
            SmbFile file = new SmbFile(toAbsoluteDirPath(path), auth);
            file.mkdir();
            return true;
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
            return false;
        }
    }

    @Override
    public boolean deleteDirectory(String path) {

        try {
            SmbFile file = new SmbFile(toAbsoluteDirPath(path), auth);
            file.delete();
            return true;
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
            return false;
        }
    }

    @Override
    public boolean deleteFile(String path) {

        try {
            SmbFile file = new SmbFile(toAbsoluteFilePath(path), auth);
            file.delete();
            return true;
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
            return false;
        }
    }

    @Override
    public boolean isMoveFileSupported() {
        return true;
    }

    @Override
    public boolean moveFile(String oldPath, String newPath) {

        try {
            SmbFile oldFile = new SmbFile(toAbsoluteFilePath(oldPath), auth);
            SmbFile newFile = new SmbFile(toAbsoluteFilePath(newPath), auth);
            oldFile.renameTo(newFile);
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
            return false;
        }

        return true;
    }

    @Override
    public boolean writeFile(InputStream fileStream, FileSnapshot fileInfo) {

        if (fileStream == null)
            return false;

        OutputStream out = null;
        long bytesWritten = 0;
        boolean setTimestamp = false;

        try {
            SmbFile file = new SmbFile(toAbsoluteFilePath(fileInfo.getRelativePath()), auth);
            out = file.getOutputStream();

            if (out == null) {
                System.out.println("Failed to open file for write: " + fileInfo.getRelativePath());
            }

            if (fileInfo.isLargeFile()) {
                bytesWritten = IOUtils.copyLarge(fileStream, out);
            } else {
                bytesWritten = IOUtils.copy(fileStream, out);
            }
        } catch (IOException ex) {
            System.out.println("Failed to copy file: " + ex.getMessage());
        } finally {
            try {
                if (fileStream != null)
                    fileStream.close();
                if (out != null)
                    out.close();
            } catch (IOException ex) {
                System.out.println("Failed to close stream: " + ex.getMessage());
            }
        }

        try {
            SmbFile file = new SmbFile(toAbsoluteFilePath(fileInfo.getRelativePath()), auth);
            file.setLastModified(fileInfo.getModifiedTimestamp().toDate().getTime());
            setTimestamp = true;
        } catch (IOException ex) {
            System.out.println("Failed to copy file: " + ex.getMessage());
        }

        return setTimestamp && (bytesWritten == fileInfo.getFileSize());
    }

    private final static SmbFileFilter filter = new SmbFileFilter() {

        @Override
        public boolean accept(SmbFile file) throws SmbException {
            return !file.isHidden();
        }
    };

    private SmbFile[] listFiles(SmbFile folder) throws SmbException {

        SmbFile[] files = null;
        int attemptCount = 0;

        while ((files == null) && (attemptCount < 3)) {
            try {
                attemptCount++;
                files = folder.listFiles(filter);
            } catch (SmbException ex) {
                if (attemptCount < 3) {
                    System.out.println("Failed to list files for " + folder.getPath() + ", retrying.");
                } else {
                    throw ex;
                }
            }
        }

        return files;
    }

    private Boolean isFile(final SmbFile file) throws SmbException {

        Boolean isFile = null;
        int attemptCount = 0;

        while ((isFile == null) && (attemptCount < 3)) {
            try {
                isFile = file.isFile();
                attemptCount++;
            } catch (SmbException ex) {
                if (attemptCount < 3) {
                    System.out.println("Failed to query file " + file.getPath() + ", retrying.");
                } else {
                    throw ex;
                }
            }
        }

        return isFile;
    }

    private Boolean isDirectory(final SmbFile file) throws SmbException {

        Boolean isDirectory = null;
        int attemptCount = 0;

        while ((isDirectory == null) && (attemptCount < 3)) {
            try {
                isDirectory = file.isDirectory();
                attemptCount++;
            } catch (SmbException ex) {
                if (attemptCount < 3) {
                    System.out.println("Failed to query file " + file.getPath() + ", retrying.");
                } else {
                    throw ex;
                }
            }
        }

        return isDirectory;
    }

    private FileSnapshot createFileSnapshot(final SmbFile file, String path) throws SmbException {

        Long modifiedDate = null;
        Long length = null;

        int attemptCount = 0;

        while (((modifiedDate == null) || (length == null)) && (attemptCount < 3)) {
            try {

                if (modifiedDate == null) {
                    modifiedDate = file.lastModified();
                    attemptCount = 0;
                }
                if (length == null) {
                    length = file.length();
                }

                attemptCount++;
            } catch (SmbException ex) {
                if (attemptCount < 3) {
                    System.out.println("Failed to query file " + file.getPath() + ", retrying.");
                } else {
                    throw ex;
                }
            }
        }

        return new FileSnapshot(file.getName(), length, new DateTime(new Date(modifiedDate)), toRelativePath(path));
    }

    private String toRelativePath(String absolutePath) {
        return toRelativePath(absolutePath, false);
    }

    private String toRelativePath(String absolutePath, boolean withTrailingSlash) {
        if (!absolutePath.startsWith(rootPath))
            return absolutePath;

        String relative = absolutePath.substring(rootPath.length());

        if (withTrailingSlash && !relative.endsWith("/")) {
            relative = relative + "/";
        }
        if (!withTrailingSlash && relative.endsWith("/")) {
            relative = relative.substring(0, relative.length() - 1);
        }

        return relative;
    }

    private String toAbsoluteDirPath(String path) {
        return String.format("%s%s/", rootPath, path.endsWith("/") ? path.substring(0, path.length() - 1) : path);
    }

    private String toAbsoluteFilePath(String relativePath) {
        return String.format("%s%s", rootPath, relativePath);
    }
}