com.mediaworx.intellij.opencmsplugin.sync.SyncFileAnalyzer.java Source code

Java tutorial

Introduction

Here is the source code for com.mediaworx.intellij.opencmsplugin.sync.SyncFileAnalyzer.java

Source

/*
 * This file is part of the OpenCms plugin for IntelliJ by mediaworx.
 *
 * For further information about the OpenCms plugin for IntelliJ, please
 * see the project website at GitHub:
 * https://github.com/mediaworx/opencms-intellijplugin
 *
 * Copyright (C) 2007-2016 mediaworx berlin AG (http://www.mediaworx.com)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 3 of the License, or (at your
 * option) any later version.
 *
 * 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 General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package com.mediaworx.intellij.opencmsplugin.sync;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
import com.mediaworx.intellij.opencmsplugin.OpenCmsPlugin;
import com.mediaworx.intellij.opencmsplugin.entities.SyncFile;
import com.mediaworx.intellij.opencmsplugin.entities.SyncFolder;
import com.mediaworx.intellij.opencmsplugin.exceptions.CmsConnectionException;
import com.mediaworx.intellij.opencmsplugin.exceptions.CmsPermissionDeniedException;
import com.mediaworx.intellij.opencmsplugin.opencms.OpenCmsModule;
import com.mediaworx.intellij.opencmsplugin.opencms.OpenCmsModuleResource;
import com.mediaworx.intellij.opencmsplugin.tools.PluginTools;
import com.mediaworx.intellij.opencmsplugin.tools.VfsFileAnalyzer;
import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.client.api.Folder;
import org.apache.chemistry.opencmis.client.api.ItemIterable;
import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;

import java.io.File;
import java.util.*;

class SyncFileAnalyzer extends VfsFileAnalyzer implements Runnable {

    private static final Logger LOG = Logger.getInstance(SyncFileAnalyzer.class);

    private SyncList syncList;
    List<OpenCmsModuleResource> moduleResourcesToBePulled;

    private VfsAdapter vfsAdapter;

    private static final String CLASSES_FOLDER = "/classes";

    private boolean pullAllMetaInformation;
    private boolean executeSync = true;

    SyncFileAnalyzer(final OpenCmsPlugin plugin, final List<File> syncFiles, boolean pullAllMetaInformation)
            throws CmsConnectionException {

        super(plugin, syncFiles);

        this.pullAllMetaInformation = pullAllMetaInformation;
        syncList = new SyncList();
        syncList.setPullMetaDataOnly(pullAllMetaInformation);

        vfsAdapter = plugin.getVfsAdapter();

        // Not connected yet (maybe OpenCms wasn't started when the project opened)
        if (!vfsAdapter.isConnected()) {
            // Try again to connect
            vfsAdapter.startSession();
        }
        this.vfsAdapter.clearCache();

        moduleResourcesToBePulled = new ArrayList<OpenCmsModuleResource>();
    }

    @Override
    public void run() {
        progressIndicator = ProgressManager.getInstance().getProgressIndicator();
        progressIndicator.setIndeterminate(true);
        progressIndicator.setText("Calculating resources to sync, please wait");

        analyzeFiles();

        if (!progressIndicator.isCanceled()) {
            if (moduleResourcesToBePulled != null && moduleResourcesToBePulled.size() > 0) {
                handleModuleResourcesToBePulled(moduleResourcesToBePulled);
            }
        } else {
            executeSync = false;
        }
    }

    boolean isExecuteSync() {
        return executeSync;
    }

    protected void handleModule(OpenCmsModule ocmsModule) {
        super.handleModule(ocmsModule);
        syncList.setSyncModuleMetaData(true);
        syncList.addOcmsModule(ocmsModule);
    }

    protected void handleModuleResourcePath(OpenCmsModule ocmsModule, String moduleResourceVfsPath) {
        LOG.info("resource path: " + ocmsModule.getLocalVfsRoot() + moduleResourceVfsPath);

        File resourceFile = new File(ocmsModule.getLocalVfsRoot() + moduleResourceVfsPath);
        if (resourceFile.exists()) {
            LOG.info("vFolder path: " + PluginTools.ensureUnixPath(resourceFile.getPath()));
            handleModuleResource(ocmsModule, resourceFile);
        } else {
            LOG.info("Resource path doesn't exist in the FS, it has to be pulled from the VFS");
            moduleResourcesToBePulled.add(new OpenCmsModuleResource(ocmsModule, moduleResourceVfsPath));
        }
    }

    protected void handleModuleResource(OpenCmsModule ocmsModule, File file) {
        walkFileTree(ocmsModule, file, FolderSyncMode.AUTO);
    }

    // TODO: handle cases where a folder on the vfs has the same name as a file on the rfs or vice versa
    private void walkFileTree(OpenCmsModule ocmsModule, File file, FolderSyncMode folderSyncMode) {

        if (progressIndicator.isCanceled()) {
            executeSync = false;
            return;
        }

        // the file has already been handled, so skip
        if (fileWasHandled(file)) {
            LOG.info("already handled " + file.getPath() + ", skipping");
            return;
        } else {
            addHandledFile(file);
        }

        if (fileOrPathIsIgnored(plugin.getPluginConfiguration(), file)) {
            return;
        }

        String vfsPath = ocmsModule.getVfsPathForFile(file);

        LOG.info("VFS path is " + vfsPath);

        boolean vfsObjectExists;
        CmisObject vfsObject = null;

        // it is known, that the VFS resource does not exist (because a descendant of a nonexistent folder is handled)
        if (folderSyncMode == FolderSyncMode.PUSH) {
            vfsObjectExists = false;
        }
        // the VFS resource might exist
        else {
            // get the corresponding vfs object (if it exists)
            try {
                vfsObject = vfsAdapter.getVfsObject(vfsPath);
            } catch (CmsPermissionDeniedException e) {
                String message = "Skipping " + vfsPath + ", permission denied\n";
                LOG.info(message, e);
                warnings.append(message).append("\n");
                return;
            }

            vfsObjectExists = vfsObject != null;
            LOG.debug(vfsPath + (vfsObjectExists ? " exists" : " does not exist"));
        }

        // It's a folder, check if it is already there and compare contents
        if (file.isDirectory()) {
            // The folder is not there, so push it with all child contents
            if (!vfsObjectExists) {
                if (!pullAllMetaInformation) {
                    LOG.info("It's a folder that does not exist on the VFS, PUSH recursively");
                    addRfsOnlyFolderTreeToSyncList(ocmsModule, vfsPath, file, false);
                }
            }
            // The Folder is there, compare contents of VFS and RFS
            else {
                handleExistingFolder(ocmsModule, file, (Folder) vfsObject, vfsPath);
            }
        }
        // It's a file
        else {
            // The file is not there, so push it
            if (!vfsObjectExists) {
                if (!pullAllMetaInformation) {
                    LOG.info("It's a file that does not exist on the VFS, PUSH");
                    addRfsOnlyFileToSyncList(ocmsModule, vfsPath, file, null);
                }
            }
            // The file exists, check which one is newer
            else {
                handleExistingFile(ocmsModule, file, vfsObject, vfsPath);
            }
        }

    }

    private void handleExistingFolder(OpenCmsModule ocmsModule, File file, Folder vfsObject, String vfsPath) {
        LOG.info("It's a folder that does exist on the VFS, compare");

        // Get folder content from the vfs, put it in a set
        LOG.info("Getting VFS content");
        LOG.info("Children:");

        if (pullAllMetaInformation) {
            syncList.add(new SyncFolder(ocmsModule, vfsPath, file, vfsObject, SyncAction.PULL, true));
        }

        ItemIterable<CmisObject> vfsChildren = vfsObject.getChildren();
        Map<String, CmisObject> vfsChildMap = new LinkedHashMap<String, CmisObject>();
        for (CmisObject vfsChild : vfsChildren) {
            vfsChildMap.put(vfsChild.getName(), vfsChild);
            LOG.info("    " + vfsChild.getName());
        }

        LOG.info("Looping RFS children");

        File[] rfsChildren = file.listFiles();

        if (rfsChildren != null && rfsChildren.length > 0) {
            // handle resources in the RFS
            for (File rfsChild : rfsChildren) {
                if (progressIndicator.isCanceled()) {
                    return;
                }
                String filename = rfsChild.getName();

                // The file/folder does not exist on the VFS, recurse in PUSH mode (all children will be pushed)
                if (!vfsChildMap.containsKey(filename)) {
                    if (!pullAllMetaInformation) {
                        LOG.info("RFS child " + rfsChild.getName() + " is not on the VFS, handle it in PUSH mode");
                        walkFileTree(ocmsModule, rfsChild, FolderSyncMode.PUSH);
                    }
                }
                // The file/folder does exist on the VFS, recurse in AUTO mode (children will be pushed or pulled depending on their date)
                else {
                    LOG.info("RFS child " + rfsChild.getName() + " exists on the VFS, handle it in AUTO mode");
                    walkFileTree(ocmsModule, rfsChild, FolderSyncMode.AUTO);

                    // remove the file from the vfsChildren map, so that only files that exist only on the vfs will be left
                    vfsChildMap.remove(filename);
                }
            }
        }

        // Handle files/folders that exist only on the vfs
        if (!pullAllMetaInformation && vfsChildMap.size() > 0) {
            handleVfsOnlyChildren(ocmsModule, vfsObject.getPath(), vfsChildMap);
        }
    }

    private void handleVfsOnlyChildren(OpenCmsModule ocmsModule, String parentVfsPath,
            Map<String, CmisObject> vfsChildMap) {
        LOG.info("Handle files/folders that exist only on the vfs");
        for (CmisObject vfsChild : vfsChildMap.values()) {
            if (progressIndicator.isCanceled()) {
                return;
            }
            String childVfsPath = parentVfsPath + vfsChild.getName();

            // files
            if (vfsChild.getBaseTypeId().equals(BaseTypeId.CMIS_DOCUMENT)) {
                addVfsOnlyFileToSyncList(ocmsModule, childVfsPath, vfsChild, false);
            }
            // folders
            else if (vfsChild.getBaseTypeId().equals(BaseTypeId.CMIS_FOLDER)) {
                addVfsOnlyFolderTreeToSyncList(ocmsModule, childVfsPath, vfsChild, false);
            }
        }
    }

    private void handleExistingFile(OpenCmsModule ocmsModule, File file, CmisObject vfsObject, String vfsPath) {
        LOG.info("It's a file that exists on the VFS and the RFS");

        if (pullAllMetaInformation) {
            syncList.add(new SyncFile(ocmsModule, vfsPath, file, vfsObject, SyncAction.PULL, true));
        } else {
            Date localDate = new Date(file.lastModified());
            Date vfsDate = vfsObject.getLastModificationDate().getTime();

            if (ocmsModule.getSyncMode() == SyncMode.SYNC) {
                LOG.info("SyncMode is SYNC, so compare dates");
                if (localDate.after(vfsDate)) {
                    LOG.info("RFS file is newer, PUSH");
                    syncList.add(new SyncFile(ocmsModule, vfsPath, file, vfsObject, SyncAction.PUSH, true));
                } else if (vfsDate.after(localDate)) {
                    LOG.info("VFS file is newer, PULL");
                    syncList.add(new SyncFile(ocmsModule, vfsPath, file, vfsObject, SyncAction.PULL, true));
                } else {
                    LOG.info("VFS file and RFS file have the same date, ignore");
                }
            }
            // if the dates are different, add the resource with PUSH or PULL action, depending on the module's syncMode
            else if (vfsDate.compareTo(localDate) != 0) {
                SyncAction syncAction = ocmsModule.getSyncMode() == SyncMode.PUSH ? SyncAction.PUSH
                        : SyncAction.PULL;
                LOG.info("SyncMode is " + ocmsModule.getSyncMode() + " and files are not equal, so force "
                        + syncAction);
                syncList.add(new SyncFile(ocmsModule, vfsPath, file, vfsObject, syncAction, true));
            }
        }
    }

    private void handleModuleResourcesToBePulled(List<OpenCmsModuleResource> moduleResourcesToBePulled) {
        for (OpenCmsModuleResource moduleResourceToBePulled : moduleResourcesToBePulled) {
            if (progressIndicator.isCanceled()) {
                executeSync = false;
                return;
            }

            String vfsPath = moduleResourceToBePulled.getResourcePath();

            CmisObject vfsObject;
            try {
                vfsObject = vfsAdapter.getVfsObject(vfsPath);
            } catch (CmsPermissionDeniedException e) {
                warnings.append("Skipping ").append(vfsPath).append(", permission denied\n");
                continue;
            }
            if (vfsObject == null) {
                warnings.append("Skipping ").append(vfsPath).append(", doesn't exist in the VFS\n");
                continue;
            }

            OpenCmsModule ocmsModule = moduleResourceToBePulled.getOpenCmsModule();

            // files
            if (vfsObject.getBaseTypeId().equals(BaseTypeId.CMIS_DOCUMENT)) {
                addModuleResourceFileToSyncList(ocmsModule, vfsPath, vfsObject);
            }
            // folders
            else if (vfsObject.getBaseTypeId().equals(BaseTypeId.CMIS_FOLDER)) {
                addModuleResourceFolderTreeToSyncList(ocmsModule, vfsPath, vfsObject);
            }
        }
    }

    private void addRfsOnlyFileToSyncList(OpenCmsModule ocmsModule, String vfsPath, File file, Document vfsFile) {
        LOG.info("Adding RFS only file " + vfsPath);
        SyncAction syncAction = getRfsOnlySyncAction(ocmsModule.getSyncMode());
        SyncFile syncFile = new SyncFile(ocmsModule, vfsPath, file, vfsFile, syncAction, vfsFile != null);
        syncList.add(syncFile);
    }

    private void addRfsOnlyFolderTreeToSyncList(OpenCmsModule ocmsModule, String vfsPath, File file,
            boolean replaceExistingEntity) {
        LOG.info("Adding RFS only folder " + vfsPath);

        SyncAction syncAction = getRfsOnlySyncAction(ocmsModule.getSyncMode());
        SyncFolder syncFolder = new SyncFolder(ocmsModule, vfsPath, file, null, syncAction, replaceExistingEntity);
        syncList.add(syncFolder);

        if (syncAction != SyncAction.DELETE_RFS) {
            LOG.info("Get children of folder " + vfsPath);
            Collection<File> rfsChildren = FileUtils.listFiles(file, TrueFileFilter.INSTANCE, null);
            for (File rfsChild : rfsChildren) {
                LOG.info("Handle PUSH child " + rfsChild.getPath());
                walkFileTree(ocmsModule, rfsChild, FolderSyncMode.PUSH);
            }
        }
    }

    private void addVfsOnlyFileToSyncList(OpenCmsModule ocmsModule, String vfsPath, CmisObject vfsObject,
            boolean replaceExistingEntity) {
        LOG.info("Adding VFS only file " + vfsPath);
        SyncAction syncAction = getVfsOnlySyncAction(ocmsModule.getSyncMode());
        SyncFile syncFile = new SyncFile(ocmsModule, vfsPath, null, vfsObject, syncAction, replaceExistingEntity);
        syncList.add(syncFile);
    }

    private void addVfsOnlyFolderTreeToSyncList(OpenCmsModule ocmsModule, String vfsPath, CmisObject vfsObject,
            boolean replaceExistingEntity) {
        LOG.info("Adding VFS only folder " + vfsPath);

        SyncAction syncAction = getVfsOnlySyncAction(ocmsModule.getSyncMode());
        SyncFolder syncFolder = new SyncFolder(ocmsModule, vfsPath, null, vfsObject, syncAction,
                replaceExistingEntity);
        syncList.add(syncFolder);

        if (syncAction != SyncAction.DELETE_VFS) {
            // traverse folder, add children to the SyncJob
            LOG.info("Get children of VFS folder " + vfsPath);
            ItemIterable<CmisObject> vfsChildren = ((Folder) vfsObject).getChildren();
            for (CmisObject child : vfsChildren) {
                String childVfsPath = vfsPath + "/" + child.getName();

                // files
                if (child.getBaseTypeId().equals(BaseTypeId.CMIS_DOCUMENT)) {
                    addVfsOnlyFileToSyncList(ocmsModule, childVfsPath, child, false);
                }
                // folders
                else if (child.getBaseTypeId().equals(BaseTypeId.CMIS_FOLDER)) {
                    addVfsOnlyFolderTreeToSyncList(ocmsModule, childVfsPath, child, false);
                }
            }
        }
    }

    private void addModuleResourceFileToSyncList(OpenCmsModule ocmsModule, String vfsPath, CmisObject vfsObject) {
        LOG.info("Adding VFS module resource file " + vfsPath);
        SyncFile syncFile = new SyncFile(ocmsModule, vfsPath, null, vfsObject, SyncAction.PULL, false);
        syncList.add(syncFile);
    }

    private void addModuleResourceFolderTreeToSyncList(OpenCmsModule ocmsModule, String vfsPath,
            CmisObject vfsObject) {
        LOG.info("Adding VFS module resource folder " + vfsPath);

        SyncFolder syncFolder = new SyncFolder(ocmsModule, vfsPath, null, vfsObject, SyncAction.PULL, false);
        syncList.add(syncFolder);

        // traverse folder, add children to the SyncJob
        LOG.info("Get children of VFS folder " + vfsPath);
        ItemIterable<CmisObject> vfsChildren = ((Folder) vfsObject).getChildren();
        for (CmisObject child : vfsChildren) {
            if (progressIndicator.isCanceled()) {
                executeSync = false;
                return;
            }
            String childVfsPath = vfsPath + "/" + child.getName();

            // files
            if (child.getBaseTypeId().equals(BaseTypeId.CMIS_DOCUMENT)) {
                addModuleResourceFileToSyncList(ocmsModule, childVfsPath, child);
            }
            // folders
            else if (child.getBaseTypeId().equals(BaseTypeId.CMIS_FOLDER)) {
                addModuleResourceFolderTreeToSyncList(ocmsModule, childVfsPath, child);
            }
        }
    }

    private SyncAction getRfsOnlySyncAction(SyncMode syncMode) {
        SyncAction syncAction;
        switch (syncMode) {
        case PULL:
            syncAction = SyncAction.DELETE_RFS;
            break;
        case PUSH:
        case SYNC:
        default:
            syncAction = SyncAction.PUSH;
            break;
        }
        return syncAction;
    }

    private SyncAction getVfsOnlySyncAction(SyncMode syncMode) {
        SyncAction syncAction;
        switch (syncMode) {
        case PUSH:
            syncAction = SyncAction.DELETE_VFS;
            break;
        case PULL:
        case SYNC:
        default:
            syncAction = SyncAction.PULL;
            break;
        }
        return syncAction;
    }

    SyncList getSyncList() {
        return syncList;
    }
}