Package com.nexirius.tools.dirsync

Source Code of com.nexirius.tools.dirsync.DirectoryInfo

//{HEADER
/**
* This class is part of jnex 'Nexirius Application Framework for Java'
* Copyright (C) Nexirius GmbH, CH-4450 Sissach, Switzerland (www.nexirius.ch)
*
* <p>This library is free software; you can redistribute it and/or<br>
* modify it under the terms of the GNU Lesser General Public<br>
* License as published by the Free Software Foundation; either<br>
* version 2.1 of the License, or (at your option) any later version.</p>
*
* <p>This library is distributed in the hope that it will be useful,<br>
* but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
* Lesser General Public License for more details.</p>
*
* <p>You should have received a copy of the GNU Lesser General Public<br>
* License along with this library; if not, write to the Free Software<br>
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA</p>
* </blockquote>
*
* <p>
* Nexirius GmbH, hereby disclaims all copyright interest in<br>
* the library jnex' 'Nexirius Application Framework for Java' written<br>
* by Marcel Baumann.</p>
*/
//}HEADER
package com.nexirius.tools.dirsync;

import com.nexirius.util.*;

import java.io.*;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.net.URL;
import java.net.MalformedURLException;

public class DirectoryInfo {

    private static final String DIR_IDENTIFIER_STRING = "D";
    public static TextToken DIR_IDENTIFIER = new TextToken(DIR_IDENTIFIER_STRING, TextToken.IDENTIFIER);

    DirectoryInfo parent;
    String name;
    ArrayList fileList = new ArrayList();
    long size = -1L;
    int files = 0;
    long hash = 0L;

    private ArrayList subdirectoryList;
    boolean done = false;
    Iterator iterator = null;
    DirectoryInfo act = null;
    private static final String DIR_INFO_FILENAME = "dirInfo.txt";

    public DirectoryInfo(String name) {
        this(name, null);
    }

    public DirectoryInfo(String name, DirectoryInfo parent) {
        if (name.endsWith(File.separator)) {
            this.name = name.substring(0, name.length() - 1);
        } else {
            this.name = name;
        }
        this.parent = parent;
    }

    public boolean isDifferent(DirectoryInfo other) {
        if (other.getSize() != getSize() || other.getHash() != getHash()) {
            return true;
        }

        return false;
    }

    private void clearLists() {
        fileList = null;
        subdirectoryList = null;
    }

    public void clearSubdirectories() {
        if (subdirectoryList == null) {
            return;
        }
        for (Iterator it = subdirectoryList.iterator(); it.hasNext();) {
            ((DirectoryInfo) it.next()).clearLists();
        }
    }

    public TextToken getIdentifier() {
        return DIR_IDENTIFIER;
    }

    public boolean isRoot() {
        return parent == null;
    }

    public long getSize() {
        return size;
    }

    public int getFiles() {
        return files;
    }

    public long getHash() {
        return hash;
    }

    public boolean isDone() {
        return done;
    }

    public ArrayList getFileList() {
        return fileList;
    }

    public ArrayList getSubdirectoryList() {
        return subdirectoryList;
    }

    public DirectoryInfo nextDirectory(IStringFilter dirFilter, IStringFilter filter) {
        if (done) {
            return null;
        }

        if (size < 0L) {
            // scan subdirectories at first call and set act to the first subdirectory and initialize hash and size to represent the file list
            scanSubdirectoriesAndFiles(dirFilter, filter);
        }

        if (act == null) {
            // no more subdirectories
            iterator = null;
            done = true;

            return this;
        }

        DirectoryInfo ret = act.nextDirectory(dirFilter, filter);

        if (ret != null) {
            // some sub sub directory found
            return ret;
        }

        // use the subdirectory information now when it has been fully scanned
        size += act.getSize();
        files += act.getFiles();
        hash += act.getHash();
        hash += getHashOf(act.name);

        // step to next subdirectory
        if (iterator.hasNext()) {
            act = (DirectoryInfo) iterator.next();
        } else {
            act = null;
        }

        return nextDirectory(dirFilter, filter); // recurse
    }

    private void scanSubdirectoriesAndFiles(IStringFilter dirFilter, IStringFilter filter) {
        size = 0L;
        String dir = getFullName(null);

        if (dir == null) {
            dir = name;
        } else {
            dir = getRootDirectory() + File.separatorChar + dir;
        }

        StringVector dirList = new XFile(dir).getDirectories(false);

        if (dirList.size() > 0) {
            subdirectoryList = new ArrayList();
            StringBuffer fullRelativeName = new StringBuffer();
            getFullName(fullRelativeName);

            for (String dirName = dirList.firstItem(); dirName != null; dirName = dirList.nextItem()) {
                try {
                    if (dirFilter == null || dirFilter.match(fullRelativeName.toString() + dirName)) {
                        subdirectoryList.add(new DirectoryInfo(dirName, this));
                    }
                } catch (Exception e) {
                    e.printStackTrace()//To change body of catch
                }
            }

            iterator = subdirectoryList.iterator();

            if (iterator.hasNext()) {
                act = (DirectoryInfo) iterator.next();
            }
        }

        StringVector fileNames = new XFile(dir).getFiles(false);

        if (filter != null) {
            StringVector filteredNames = new StringVector();

            for (String fileName = fileNames.firstItem(); fileName != null; fileName = fileNames.nextItem()) {
                try {
                    if (filter == null || filter.match(fileName)) {
                        filteredNames.append(fileName);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            fileNames = filteredNames;
        }

        files = fileNames.size();

        if (files > 0) {
            StringBuffer fileInfoStringBuffer = new StringBuffer();

            for (String fileName = fileNames.firstItem(); fileName != null; fileName = fileNames.nextItem()) {
                try {
                    XFile xf = new XFile(dir, fileName);
                    FileInfo fileInfo = generateFileInfo(xf);
                    fileInfo.name = fileName;
                    size += fileInfo.size;
                    fileInfo.getString(fileInfoStringBuffer);
                    fileList.add(fileInfo);
                } catch (Exception e) {
                    e.printStackTrace()//To change body of catch
                }
            }

            hash = getHashOf(fileInfoStringBuffer.toString());
        }
    }

    public DirectoryInfo nextDirectory() {
        return nextDirectory(null, null);
    }

    public String getFullName() {
        return getFullName(null);
    }

    public String getFullName(StringBuffer sb) {
        if (parent == null) {

            return null;
        }

        if (sb == null) {
            sb = new StringBuffer();
        }

        parent.getFullName(sb);
        sb.append(File.separatorChar);
        sb.append(name);

        return sb.toString();
    }

    public String getRootDirectory() {
        if (parent != null) {
            return parent.getRootDirectory();
        }

        return name;
    }

    public FileInfo generateFileInfo(XFile xf) throws Exception {
        if (!xf.canRead()) {

            return null;
        }

        FileInfo ret = new FileInfo();
        InputStream in = xf.getBufferedInputStream();
        getHashAndSize(in, ret);

        return ret;
    }

    private long getHashOf(String s) {
        try {
            FileInfo fi = getHashAndSize(new BufferedInputStream(new ByteArrayInputStream(s.getBytes())), null);
            return fi.hash;
        } catch (IOException e) {
            e.printStackTrace()//should never happen
        }

        return 0L;
    }

    private FileInfo getHashAndSize(InputStream in, FileInfo fileInfo) throws
            IOException {
        if (fileInfo == null) {
            fileInfo = new FileInfo();
        }

        long hash = 0L;
        long i = 1L;

        while (true) {
            int c = in.read();

            if (c < 0) {
                break;
            }

            hash += c ^ i;
            ++i;
        }

        in.close();

        fileInfo.size = i - 1L;
        fileInfo.hash = hash;

        return fileInfo;
    }

    public String toString() {
        StringBuffer sb = new StringBuffer(name);
        sb.append('\n');
        sb.append(files);
        sb.append('\n');
        sb.append(size);
        sb.append('\n');
        sb.append(hash);
        sb.append('\n');

        Iterator iter = getFileList().iterator();

        while (iter.hasNext()) {
            FileInfo file = (FileInfo) iter.next();

            file.getString(sb);
        }

        return sb.toString();
    }

    public String getName() {
        return name;
    }

    public DirectoryInfo getParentDir() {
        return parent;
    }

    /**
     * @param rootDir
     * @param result
     * @return true if the path is pointing to an existing file (false for an URL)
     */
    public boolean getPath(String rootDir, StringBuffer result) {
        if (isRoot()) {
            if (rootDir == null) {
                result.append(getName());
            } else {
                result.append(rootDir);
            }

            return new File(result.toString()).exists();
        }
        boolean ret = getParentDir().getPath(rootDir, result);
        result.append(ret ? File.separatorChar : '/');
        result.append(getName());

        return ret;
    }

    public String createDirectory(String targetDir) {
        StringBuffer dirName = new StringBuffer(1024);

        getPath(targetDir, dirName);

        XFile file = new XFile(dirName.toString());

        file.mkdirs();

        return dirName.toString();
    }

    public void writeTo(OutputStream out) throws Exception {
        new TextToken(name).writeTo(out);
        FileInfo.SPACE.writeTo(out);
        new TextToken(size).writeTo(out);
        FileInfo.SPACE.writeTo(out);
        new TextToken(hash).writeTo(out);
        FileInfo.NEW_LINE.writeTo(out);

        // write files
        Iterator iterFiles = getFileList().iterator();

        while (iterFiles.hasNext()) {
            FileInfo file = (FileInfo) iterFiles.next();

            file.writeTo(out);
        }

        if (subdirectoryList != null) {
            // write subdirectories
            Iterator dirIter = subdirectoryList.iterator();

            while (dirIter.hasNext()) {
                String subdirectory = ((DirectoryInfo) dirIter.next()).getName();

                getIdentifier().writeTo(out);
                FileInfo.SPACE.writeTo(out);
                new TextToken(subdirectory).writeTo(out);
                FileInfo.NEW_LINE.writeTo(out);
            }
        }
    }

    public void readFrom(PushbackInputStream in) throws IOException {
        TextToken token = TextToken.nextToken(in);

        if (token.isString()) {
            if (name == null) {
                name = token.getString();
            }
        } else {
            throw new IOException("Unexpected Token (expect name):" + token);
        }

        token = TextToken.nextToken(in);

        if (token.isLong()) {
            size = token.getLong();
        } else {
            throw new IOException("Unexpected Token (expect size):" + token);
        }

        token = TextToken.nextToken(in);

        if (token.isLong()) {
            hash = token.getLong();
        } else {
            throw new IOException("Unexpected Token (expect hash):" + token);
        }

        subdirectoryList = new ArrayList();
        fileList.clear();

        while (true) {
            token = TextToken.nextToken(in);

            if (token == null) {
                return;
            }

            if (token.isIdentifier(FileInfo.FILE_IDENTIFIER_STRING)) {
                // read files
                FileInfo fileInfo = new FileInfo();

                fileInfo.readFrom(in);
                fileList.add(fileInfo);
            } else if (token.isIdentifier(DIR_IDENTIFIER_STRING)) {
                // read subdirectories
                token = TextToken.nextToken(in);

                if (!token.isString()) {
                    throw new IOException("Unexpected Token (subdirectory name):" + token);
                }

                subdirectoryList.add(new DirectoryInfo(token.getString(), this));
            } else {
                throw new IOException("Unexpected Token (D or F):" + token);
            }
        }
    }

    public static void createDirInfoTree(String sourceDir, IStringFilter dirFilter, IStringFilter fileFilter, String targetDir) throws Exception {
        new XFile(targetDir).delete();
        DirectoryInfo root = new DirectoryInfo(sourceDir);

        for (DirectoryInfo dir = root.nextDirectory(dirFilter, fileFilter); dir != null; dir = root.nextDirectory(dirFilter, fileFilter))
        {
            dir.createDirInfo(targetDir);
            dir.clearSubdirectories();
        }

        root.createDirInfo(targetDir);
    }

    public void createDirInfo(String dirInfoDirectory) throws Exception {
        String dirName = createDirectory(dirInfoDirectory);
        XFile dirInfoFile = new XFile(dirName, DIR_INFO_FILENAME);
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dirInfoFile));
        writeTo(out);
        out.close();
    }

    public void readDirInfo(String dirInfoDirectory) throws IOException {
        StringBuffer dirName = new StringBuffer(1024);
        boolean isFile = getPath(dirInfoDirectory, dirName);
        PushbackInputStream in = getPushbackInputStream(dirName.toString(), DIR_INFO_FILENAME, isFile);
        readFrom(in);
        in.close();
    }

    public DirSyncManager sync(DirSyncManager dirSyncManager, DirectoryInfo targetDirectoryInfo, String srcDir, String targetDir) {
        if (dirSyncManager == null) {
            dirSyncManager = new DefaultDirSyncManager();
        }

        long volumeBefore = dirSyncManager.getActualVolume();

        // sync subdirectories
        try {
            readDirInfo(null);
        } catch (IOException e) {
            e.printStackTrace();
            dirSyncManager.setError("Cannot read dir info", e);
            return dirSyncManager;
        }

        if (isRoot()) {
            dirSyncManager.setTotalVolume(size);
        }

        if (targetDirectoryInfo != null) {
            try {
                targetDirectoryInfo.readDirInfo(null);
            } catch (IOException e) {
                dirSyncManager.setError("Cannot read dir info", e);
                return dirSyncManager;
            }

            if (!isDifferent(targetDirectoryInfo)) {
                dirSyncManager.setActualVolume(volumeBefore + size);

                return dirSyncManager;
            }
        }

        StringBuffer path1 = new StringBuffer();
        boolean isFile = getPath(srcDir, path1);
        String sourceDirName = path1.toString();
        StringBuffer path2 = new StringBuffer();
        getPath(targetDir, path2);
        String targetDirName = path2.toString();

        dirSyncManager.createDirectory(new XFile(targetDirName));

        ArrayList subdirs = getSubdirectoryList();
        ArrayList targetSubdirs = null;
        Hashtable targetSubdirMap = new Hashtable();

        if (targetDirectoryInfo != null) {
            targetSubdirs = targetDirectoryInfo.getSubdirectoryList();
            for (Iterator itTarget = targetSubdirs.iterator(); itTarget.hasNext();) {
                DirectoryInfo directoryInfo = (DirectoryInfo) itTarget.next();

                targetSubdirMap.put(directoryInfo.getName(), directoryInfo);
            }
        }

        if (subdirs != null) {
            for (Iterator it = subdirs.iterator(); it.hasNext();) {
                DirectoryInfo subdirectoryInfo = (DirectoryInfo) it.next();
                DirectoryInfo targetSubdirectoryInfo = (DirectoryInfo) targetSubdirMap.get(subdirectoryInfo.getName());
                if (targetSubdirectoryInfo == null) {
                    // create target subdirectory
                    subdirectoryInfo.sync(dirSyncManager, null, srcDir, targetDir);
                } else {
                    targetSubdirMap.remove(targetSubdirectoryInfo.getName());
                    // sync
                    subdirectoryInfo.sync(dirSyncManager, targetSubdirectoryInfo, srcDir, targetDir);
                }
            }
        }

        // delete remaining directories on target
        for (Iterator itDelete = targetSubdirMap.keySet().iterator(); itDelete.hasNext();) {
            DirectoryInfo directoryInfo = (DirectoryInfo) targetSubdirMap.get(itDelete.next());

            dirSyncManager.removeDirectory(targetDirName, directoryInfo.getName());
        }

        // sync files
        ArrayList fileList = getFileList();
        Hashtable targetFileMap = new Hashtable();

        if (targetDirectoryInfo != null) {
            ArrayList targetFileList = targetDirectoryInfo.getFileList();

            for (Iterator itTarget = targetFileList.iterator(); itTarget.hasNext();) {
                FileInfo fileInfo = (FileInfo) itTarget.next();

                targetFileMap.put(fileInfo.getName(), fileInfo);
            }
        }

        for (Iterator it = fileList.iterator(); it.hasNext();) {
            FileInfo fileInfo = (FileInfo) it.next();
            FileInfo targetFileInfo = (FileInfo) targetFileMap.get(fileInfo.getName());

            dirSyncManager.addActualVolume(fileInfo.size);

            if (targetFileInfo == null) {
                // create file
                XFile targetFile = new XFile(targetDirName, fileInfo.getName());

                try {
                    dirSyncManager.createFile(getPushbackInputStream(sourceDirName, fileInfo.getName(), isFile), targetFile);
                } catch (Exception e) {
                    dirSyncManager.setError("Cannot create file", e);
                    return dirSyncManager;
                }
            } else {
                targetFileMap.remove(targetFileInfo.getName());
                // sync
                if (fileInfo.isDifferent(targetFileInfo)) {
                    XFile targetFile = new XFile(targetDirName, fileInfo.getName());
                    try {
                        dirSyncManager.createFile(getPushbackInputStream(sourceDirName, fileInfo.getName(), isFile), targetFile);
                    } catch (Exception e) {
                        dirSyncManager.setError("Cannot create file", e);
                        return dirSyncManager;
                    }
                }
            }
        }
        if (targetFileMap.size() > 0) {
            StringBuffer subdirectory = new StringBuffer();
            getPath(null, subdirectory);

            // delete remaining files on target
            for (Iterator itDelete = targetFileMap.keySet().iterator(); itDelete.hasNext();) {
                FileInfo fileInfo = (FileInfo) targetFileMap.get(itDelete.next());

                dirSyncManager.removeFile(targetDir, subdirectory.toString(), fileInfo.getName());
            }
        }

        return dirSyncManager;
    }

    private static PushbackInputStream getPushbackInputStream(String dirName, String fileName, boolean isFile) {
        if (isFile) {
            File file = new File(dirName, fileName);
            if (file.canRead()) {
                try {
                    return new PushbackInputStream(new FileInputStream(file));
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                    // should never happen
                }
            }
        } else {
            try {
                URL url = new URL(dirName + '/' + fileName);

                return new PushbackInputStream(url.openStream());
            } catch (MalformedURLException e) {
                e.printStackTrace()//TODO
            } catch (IOException e) {
                e.printStackTrace()//TODO
            }
        }

        return new PushbackInputStream(new ByteArrayInputStream(new byte[0]));
    }

    public static void main(String argv[]) {
        String srcDir = "C:\\temp\\foo3";
        DirectoryInfo d = new DirectoryInfo(srcDir);

        while (true) {
            DirectoryInfo dir = d.nextDirectory(null, /*new FilterModel("\"*\"- \"*i*\"", "filterOr")*/null);
            if (dir == null) {
                break;
            }
            System.out.println(dir);
        }

        try {
            String trgDir = "C:\\temp\\dirSync_backup_foo3";
            String dirInfoSrc = "c:\\temp\\dirInfo_src";
            String dirInfoTarget = "c:\\temp\\dirInfo_trg";

            DirectoryInfo.createDirInfoTree(srcDir, new StringFilter("*"), new StringFilter("*"), dirInfoSrc);
            DirectoryInfo.createDirInfoTree(trgDir, new StringFilter("*"), new StringFilter("*"), dirInfoTarget);

            String srcDirURL = new File(srcDir).toURL().toString();
            String dirInfoSrcURL = new File(dirInfoSrc).toURL().toString();
            DirSyncManager mngr = new DirectoryInfo(dirInfoSrcURL).sync(null, new DirectoryInfo(dirInfoTarget), srcDirURL, trgDir);

            System.out.println("mngr = " + mngr);

            //DirectoryInfo.createDirInfoTree("c:\\temp", new StringFilter("*"), new StringFilter("*"), "c:\\tmp\\dirInfo");

        } catch (Exception e) {
            e.printStackTrace()//TODO
        }
    }
}
TOP

Related Classes of com.nexirius.tools.dirsync.DirectoryInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.