com.abiquo.am.services.filesystem.TemplateFileSystem.java Source code

Java tutorial

Introduction

Here is the source code for com.abiquo.am.services.filesystem.TemplateFileSystem.java

Source

/**
 * Abiquo community edition
 * cloud management application for hybrid clouds
 * Copyright (C) 2008-2010 - Abiquo Holdings S.L.
 *
 * This application is free software; you can redistribute it and/or
 * modify it under the terms of the GNU LESSER GENERAL PUBLIC
 * LICENSE as published by the Free Software Foundation under
 * version 3 of the License
 *
 * This software 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 v.3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

package com.abiquo.am.services.filesystem;

import static com.abiquo.am.services.TemplateConventions.END_OF_FILE_MARK;
import static com.abiquo.am.services.TemplateConventions.FORMATS_PATH;
import static com.abiquo.am.services.TemplateConventions.OVF_BUNDLE_IMPORTED_PREFIX;
import static com.abiquo.am.services.TemplateConventions.TEMPLATE_STATUS_DOWNLOADING_MARK;
import static com.abiquo.am.services.TemplateConventions.TEMPLATE_STATUS_ERROR_MARK;
import static com.abiquo.am.services.TemplateConventions.createBundleOvfId;
import static com.abiquo.am.services.TemplateConventions.getBundleMasterOvfId;
import static com.abiquo.am.services.TemplateConventions.getBundleSnapshot;
import static com.abiquo.am.services.TemplateConventions.getRelativeTemplatePath;
import static com.abiquo.am.services.TemplateConventions.getTemplatePath;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Scanner;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.dmtf.schemas.ovf.envelope._1.EnvelopeType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.abiquo.am.exceptions.AMError;
import com.abiquo.am.services.TemplateConventions;
import com.abiquo.am.services.filesystem.filters.BundleImageFileFilter;
import com.abiquo.am.services.filesystem.filters.FormatsFilter;
import com.abiquo.appliancemanager.exceptions.AMException;
import com.abiquo.appliancemanager.transport.TemplateStateDto;
import com.abiquo.appliancemanager.transport.TemplateStatusEnumType;
import com.abiquo.ovfmanager.ovf.OVFReferenceUtils;
import com.abiquo.ovfmanager.ovf.xml.OVFSerializer;

public class TemplateFileSystem {

    private final static Logger LOG = LoggerFactory.getLogger(TemplateFileSystem.class);

    /**
     * if (diskId == null || diskId.length() == 0) { }// remove all the package
     */
    public static EnvelopeType getEnvelope(final String enterpriseRepositoryPath, final String ovfId) {

        EnvelopeType envelope;

        String ovfPath = enterpriseRepositoryPath + getRelativeTemplatePath(ovfId);
        File ovfFile = new File(ovfPath);

        if (!ovfFile.exists()) {
            throw new AMException(AMError.TEMPLATE_NOT_FOUND, ovfId);
        }

        FileInputStream fileIs = null;
        try {
            fileIs = new FileInputStream(ovfFile);
            envelope = OVFSerializer.getInstance().readXMLEnvelope(fileIs);
        } catch (Exception e) {
            throw new AMException(AMError.TEMPLATE_MALFORMED, ovfId, e);
        } finally {
            try {
                if (fileIs != null) {
                    fileIs.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return envelope;
    }

    public static TemplateStateDto getTemplateStatus(final String enterpriseRepositoryPath, final String ovfId) {
        final TemplateStateDto state = new TemplateStateDto();
        state.setOvfId(ovfId);

        if (!TemplateConventions.isValidOVFLocation(ovfId)) {
            state.setStatus(TemplateStatusEnumType.ERROR);
            state.setErrorCause(AMError.TEMPLATE_INVALID_LOCATION.toString());
            return state;
        }

        final boolean isInstance = TemplateConventions.isBundleOvfId(ovfId);
        final String packagePath = getTemplatePath(enterpriseRepositoryPath, ovfId);

        if (isInstance) {

            final String snapshot = ovfId.substring(ovfId.lastIndexOf('/') + 1, ovfId.indexOf("-snapshot-"));
            final String masterPath = TemplateConventions.getTemplatePath(enterpriseRepositoryPath,
                    TemplateConventions.getBundleMasterOvfId(ovfId));

            final File folder = new File(masterPath);
            if (folder.list(new FilenameFilter() {
                @Override
                public boolean accept(final File file, final String name) {
                    return name.startsWith(snapshot);
                }

            }).length == 0) {
                state.setStatus(TemplateStatusEnumType.NOT_DOWNLOAD);
            } else {
                state.setStatus(TemplateStatusEnumType.DOWNLOAD);
            }

            return state;
        }

        final String ovfEnvelopePath = FilenameUtils.concat(enterpriseRepositoryPath,
                getRelativeTemplatePath(ovfId));

        File errorMarkFile = new File(packagePath + TEMPLATE_STATUS_ERROR_MARK);
        if (errorMarkFile.exists()) {
            state.setStatus(TemplateStatusEnumType.ERROR);
            state.setErrorCause(readErrorMarkFile(errorMarkFile));
        } else if (new File(packagePath + TEMPLATE_STATUS_DOWNLOADING_MARK).exists()) {
            state.setStatus(TemplateStatusEnumType.DOWNLOADING);

        } else if (!new File(ovfEnvelopePath).exists()) {
            state.setStatus(TemplateStatusEnumType.NOT_DOWNLOAD);
        } else {
            state.setStatus(TemplateStatusEnumType.DOWNLOAD);
        }

        return state;
    }

    /**
     * synch to avoid multiple changes on the package folder (before 'clearOVFStatusMarks').
     * 
     * @throws RepositoryException
     */
    public static synchronized void createTemplateStatusMarks(final String enterpriseRepositoryPath,
            final String ovfId, final TemplateStatusEnumType status, final String errorMsg) {
        final String packagePath = getTemplatePath(enterpriseRepositoryPath, ovfId);

        clearTemplateStatusMarks(packagePath);

        File mark = null;
        boolean errorCreate = false;
        try {
            switch (status) {
            case DOWNLOAD:
                // after clean the prev. marks, nothing to do.
                break;

            case NOT_DOWNLOAD: // once the OVF envelope (.ovf) is deleted its NOT_FOUND
                break;

            case DOWNLOADING:
                mark = new File(packagePath + '/' + TEMPLATE_STATUS_DOWNLOADING_MARK);
                errorCreate = !mark.createNewFile();
                break;

            case ERROR:
                mark = new File(packagePath + '/' + TEMPLATE_STATUS_ERROR_MARK);
                errorCreate = !mark.createNewFile();

                if (!errorCreate) {
                    FileWriter fileWriter = new FileWriter(mark);
                    fileWriter.append(errorMsg);
                    fileWriter.close();
                }
                break;

            default:
                throw new AMException(AMError.TEMPLATE_UNKNOW_STATUS, status.name());

            }// switch

        } catch (IOException ioe) {
            throw new AMException(AMError.TEMPLATE_CHANGE_STATUS, mark.getAbsoluteFile().getAbsolutePath());
        }

        if (errorCreate) {
            throw new AMException(AMError.TEMPLATE_CHANGE_STATUS, mark.getAbsoluteFile().getAbsolutePath());
        }
    }

    private static void clearTemplateStatusMarks(final String packagePath) {
        File errorMarkFile = new File(packagePath + TEMPLATE_STATUS_ERROR_MARK);
        File downloadingMarkFile = new File(packagePath + TEMPLATE_STATUS_DOWNLOADING_MARK);

        if (errorMarkFile.exists()) {
            if (!errorMarkFile.delete()) {
                throw new AMException(AMError.TEMPLATE_CHANGE_STATUS,
                        "removing " + errorMarkFile.getAbsolutePath());
            }
        }

        if (downloadingMarkFile.exists()) {
            if (!downloadingMarkFile.delete()) {
                throw new AMException(AMError.TEMPLATE_CHANGE_STATUS,
                        "removing " + downloadingMarkFile.getAbsolutePath());
            }
        }
    }

    private static String readErrorMarkFile(final File errorMarkFile) {
        assert errorMarkFile.exists();

        Scanner errorMarkReader = null;

        try {
            errorMarkReader = new Scanner(errorMarkFile).useDelimiter(END_OF_FILE_MARK);
        } catch (FileNotFoundException e) {
            // was checked
        }

        return errorMarkReader.next();
    }

    public static File getFileByPath(final String filePath) {
        File f = new File(filePath);
        if (!f.exists()) {
            throw new AMException(AMError.DISK_FILE_NOT_FOUND, filePath);
        }

        return f;
    }

    public static void copyFileToTemplatePath(final String packagePath, final File file) {
        // Transfer the upload content into the repository file system
        final String filePath = packagePath + file.getName();

        File f = new File(filePath);
        // TODO check do not exist and can be created

        try {
            FileUtils.moveFile(file, f);
        } catch (IOException e) {
            throw new AMException(AMError.DISK_FILE_MOVE, packagePath, e);

        }
    }

    private static void createTemplateFormatsFolder(final String packagePath) {

        final String formatsPath = packagePath + '/' + FORMATS_PATH;

        File formatsFolder = new File(formatsPath);

        if (!formatsFolder.exists())
        // !! XXX assume if the enterpriseRepositoryPath can be written then also all the package
        // and formats path.
        {
            if (!formatsFolder.mkdir()) {
                // throw new AMException(AMError.TEMPLATE_INSTALL, "creating format folder");

            }
        }
    }

    public static void createTemplateFolder(final String enterpriseRepositoryPath, final String ovfId) {

        final String packagePath = getTemplatePath(enterpriseRepositoryPath, ovfId);
        // final String packageName = repository.getOVFPackageName(ovfId);
        // should be equals to concatenation

        // just create the folder
        File packFile = new File(packagePath);

        if (!packFile.exists()) {
            if (!packFile.mkdirs()) {
                // throw new AMException(AMError.TEMPLATE_INSTALL, packagePath);

            }
        }

        createTemplateFormatsFolder(packagePath);
    }

    /**
     * Write the OVF envelope file to the OVF package folder.
     * 
     * @param envelpePath, path on the Enterprise Repository identifying the current OVF.
     * @param envelope, the OVF envelope document to be write.
     * @param description, the OVF description associated. Change its OVFFile attribute to AM's
     *            internal repository relative path.
     * @throws RepositoryException, if some error occurs during this process, The package already
     *             was being deployed.
     */
    public static void writeOVFEnvelopeToTemplateFolder(final String envelopePath, final EnvelopeType envelope) {

        File envelopeFile = new File(envelopePath);

        if (envelopeFile.exists()) {
            throw new AMException(AMError.TEMPLATE_INSTALL, "already exist");
        }

        try {
            if (!envelopeFile.createNewFile()) {
                throw new AMException(AMError.TEMPLATE_INSTALL, envelopePath);
            }
        } catch (IOException e) {
            throw new AMException(AMError.TEMPLATE_INSTALL, envelopePath);
        }

        FileOutputStream envelopeStream = null;
        try {
            envelopeStream = new FileOutputStream(envelopeFile);
            OVFSerializer.getInstance().writeXML(envelope, envelopeStream);
        } catch (Exception e1) // IOException or XMLException
        {
            throw new AMException(AMError.TEMPLATE_INSTALL, envelopePath, e1);
        } finally {
            if (envelopeStream != null) {
                try {
                    envelopeStream.close();
                } catch (IOException e) {
                    throw new AMException(AMError.TEMPLATE_INSTALL, envelopePath);
                }
            }
        } // finally
    }

    public static void deleteBundleConversion(final String packagePath, final String fileName) {
        final String formatsPath = packagePath + "formats";

        String[] formatFiles = new File(formatsPath).list(new FormatsFilter(fileName));

        for (String formatFile : formatFiles) {
            final String filePath = formatsPath + formatFile;
            final File f = new File(filePath);

            // file should exist, just retrieved from filenamefilter
            if (!f.delete()) {
                final String cause = String.format("Can not delte the converted disk at [%s]", filePath);
                LOG.error(cause);
            }
        }
    }

    public static void deleteTemplate(final String packagePath) {
        File packageFile = new File(packagePath);
        String[] bundles = packageFile.list(new BundleImageFileFilter());
        if (bundles == null || bundles.length == 0) {
            LOG.debug("There are any bundle, deleting all the folder");
            try {
                FileUtils.deleteDirectory(packageFile);
            } catch (IOException e) {
                // caused by .nfs temp files (try retry in 5s)
                if (e instanceof FileNotFoundException) {
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }

                    try {
                        FileUtils.deleteDirectory(packageFile);
                    } catch (IOException e1) {
                        throw new AMException(AMError.TEMPLATE_DELETE, packageFile.getAbsolutePath(), e1);
                    }
                } // nfs issue

            }
            return;
        } else {
            final StringBuffer stBuffer = new StringBuffer();
            stBuffer.append("The selected Template has snapshot instances associates:");
            for (String bund : bundles) {
                stBuffer.append("\n" + bund);
            }

            stBuffer.append("\n It can not be deleted.");

            throw new AMException(AMError.TEMPLATE_DELETE_INSTANCES, stBuffer.toString());
        }
    }

    /**
     * imported bundles do not use the ''enterpriserepopath''
     */
    public static void deleteImportedBundle(final String BASE_REPO_PATH, final String ovfId) {
        final String path = ovfId.substring(OVF_BUNDLE_IMPORTED_PREFIX.length(), ovfId.lastIndexOf('/'));
        final String absPath = BASE_REPO_PATH + path;

        File importBundleDir = new File(absPath);

        if (!importBundleDir.exists() || !importBundleDir.isDirectory()) {
            throw new AMException(AMError.TEMPLATE_SNAPSHOT_IMPORT_NOT_EXIST, ovfId);
        }

        try {
            FileUtils.deleteDirectory(importBundleDir);
        } catch (IOException e) {
            LOG.error("Can not delete the bundle of an imported virtual machine, on folder {}", absPath);
        }
    }

    public static void deleteBundle(final String enterpriseRepositoryPath, final String ovfId) {
        final String masterOvf = getBundleMasterOvfId(ovfId);
        final String snapshot = getBundleSnapshot(ovfId);

        final String packagePath = getTemplatePath(enterpriseRepositoryPath, ovfId);
        final EnvelopeType envelope = getEnvelope(enterpriseRepositoryPath, masterOvf);
        Set<String> fileLocations = OVFReferenceUtils.getAllReferencedFileLocations(envelope);

        for (String fileLocation : fileLocations) {
            final String absoultePath = packagePath + fileLocation;
            final String bundleAbsoultePath = createBundleOvfId(absoultePath, snapshot);

            File file = new File(bundleAbsoultePath);

            if (!file.exists()) {
                LOG.warn("Path [{}] not exist, try to remove files starting with [{}]", absoultePath, snapshot);

                String[] filesStarting = new File(packagePath).list(new FormatsFilter(snapshot));

                if (filesStarting != null) {
                    for (String fileStart : filesStarting) {
                        File fileStartFile = new File(packagePath + fileStart);
                        if (!fileStartFile.delete()) {
                            LOG.error("Try to remove the path [{}] but is not possible", fileStart);
                        }
                    }
                }
            } else {
                if (!file.delete()) {
                    LOG.error("Try to remove the path [{}] but is not possible", absoultePath);
                }
            }

            final String relativePath = bundleAbsoultePath.substring(bundleAbsoultePath.lastIndexOf('/') + 1);
            deleteBundleConversion(packagePath, relativePath);
        } // all files

        final String envelopePath = enterpriseRepositoryPath + getRelativeTemplatePath(ovfId);
        new File(envelopePath).delete();
    }
}