/**
* 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;
import static com.abiquo.am.services.TemplateConventions.OVF_BUNDLE_PATH_IDENTIFIER;
import static com.abiquo.am.services.TemplateConventions.OVF_LOCATION_PREFIX;
import static com.abiquo.am.services.TemplateConventions.codifyBundleOVFId;
import static com.abiquo.am.services.TemplateConventions.codifyEnterpriseRepositoryPath;
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.getMasterOVFPackage;
import static com.abiquo.am.services.TemplateConventions.getOVFPackageName;
import static com.abiquo.am.services.TemplateConventions.getRelativePackagePath;
import static com.abiquo.am.services.TemplateConventions.getRelativeTemplatePath;
import static com.abiquo.am.services.TemplateConventions.getTemplatePath;
import static com.abiquo.am.services.TemplateConventions.isBundleOvfId;
import static com.abiquo.am.services.TemplateConventions.isImportedBundleOvfId;
import static com.abiquo.am.services.filesystem.EnterpriseRepositoryFileSystem.validateEnterpirseRepositoryPathFile;
import static com.abiquo.am.services.filesystem.TemplateFileSystem.getEnvelope;
import static com.abiquo.am.services.filesystem.TemplateFileSystem.getFileByPath;
import static com.abiquo.am.services.filesystem.TemplateFileSystem.writeOVFEnvelopeToTemplateFolder;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import org.dmtf.schemas.ovf.envelope._1.EnvelopeType;
import org.dmtf.schemas.ovf.envelope._1.FileType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.abiquo.am.data.AMRedisDao;
import com.abiquo.am.exceptions.AMError;
import com.abiquo.am.services.filesystem.EnterpriseRepositoryFileSystem;
import com.abiquo.am.services.filesystem.TemplateFileSystem;
import com.abiquo.am.services.ovfformat.TemplateFromOVFEnvelope;
import com.abiquo.am.services.ovfformat.TemplateToOVFEnvelope;
import com.abiquo.appliancemanager.config.AMConfiguration;
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.exceptions.IdNotFoundException;
import com.abiquo.ovfmanager.ovf.exceptions.XMLException;
import com.abiquo.ovfmanager.ovf.xml.OVFSerializer;
/**
* Each enterprise have its own logical separation on the current physical Repository. This is
* implemented using a folder (with the Enterprise identifier)
*/
public class EnterpriseRepositoryService
{
private final static Logger LOG = LoggerFactory.getLogger(EnterpriseRepositoryService.class);
private final static String BASE_REPO_PATH = AMConfiguration.getRepositoryPath();
/** Repository path particular of the current enterprise. */
private final String erepoPath;
private final String erId;
/**
* Created in {@link ErepoFactory}
*/
protected EnterpriseRepositoryService(final String idEnterprise)
{
this.erId = idEnterprise;
this.erepoPath = codifyEnterpriseRepositoryPath(BASE_REPO_PATH, idEnterprise);
validateEnterpirseRepositoryPathFile(erepoPath);
LOG.debug("Create repository index for {} ", erepoPath);
List<TemplateStateDto> availables =
EnterpriseRepositoryFileSystem.getAllOVF(erepoPath, false);
AMRedisDao dao = AMRedisDao.getDao();
try
{
dao.init(idEnterprise, availables);
}
finally
{
AMRedisDao.returnDao(dao);
}
}
public List<TemplateStateDto> getTemplateStates()
{
final List<TemplateStateDto> states;
AMRedisDao dao = AMRedisDao.getDao();
try
{
states = dao.getAll(erId);
}
finally
{
AMRedisDao.returnDao(dao);
}
return states;
}
/** ########## OVF DIRECT ACCESS ########## **/
/**
* Create the folder and write to it the OVF.
*
* @return the OVF envelope document obtained form the OVF location.
* @throws RepositoryException, if can not create any of the required folders on the Enterprise
* Repository.
*/
public EnvelopeType createTemplateFolder(final String ovfId, final EnvelopeType envelope)
{
final String envelopePath = erepoPath + getRelativeTemplatePath(ovfId); // XXX
writeOVFEnvelopeToTemplateFolder(envelopePath, envelope);
return envelope;
}
public void createTemplateFolder(final String ovfId)
{
TemplateFileSystem.createTemplateFolder(erepoPath, ovfId);
}
/** Transfer the upload content into the repository file system */
public void copyFileToOVFPackagePath(final String ovfid, final File file)
{
final String packagePAth = getTemplatePath(erepoPath, ovfid);
TemplateFileSystem.copyFileToTemplatePath(packagePAth, file);
}
/***
* @throws IdNotFoundException, if the OVF package do not exist or is not on DOWNLOAD state.
*/
public void deleteTemplate(final String ovfId)
{
if (isImportedBundleOvfId(ovfId))
{
deleteImportedBundle(ovfId);
return;
}
if (isBundleOvfId(ovfId))
{
deleteBundle(ovfId);
return;
}
TemplateStateDto state = getTemplateStatus(ovfId);
if (state.getStatus() == TemplateStatusEnumType.NOT_DOWNLOAD)
{
// already deleted
return;
}
final String packagePath = getTemplatePath(erepoPath, ovfId);
TemplateFileSystem.deleteTemplate(packagePath);
}
public String path()
{
return erepoPath;
}
/** ########## DISC ########## */
public String getDiskFilePath(final String ovfid)
{
EnvelopeType envelope = null;
FileType file = null;
envelope = getEnvelope(erepoPath, ovfid);
final String diskFileId = TemplateFromOVFEnvelope.getDisk(envelope).getFileRef();
try
{
file = OVFReferenceUtils.getReferencedFile(envelope, diskFileId);
}
catch (IdNotFoundException e)
{
throw new AMException(AMError.TEMPLATE_INVALID, "Disk id not found on the envelope");
}
return file.getHref();
}
public File getOVFDiskFile(final String ovfId)
{
boolean isBundle = isBundleOvfId(ovfId);
final String ovfPath = erepoPath + getRelativeTemplatePath(ovfId);
String masterOvfId;
if (!isBundle)
{
masterOvfId = ovfId;
}
else
{
masterOvfId = getBundleMasterOvfId(ovfId);
}
final String relPath = getDiskFilePath(masterOvfId);
final String ovfFolder = ovfPath.substring(0, ovfPath.lastIndexOf('/'));
String filePath = ovfFolder + '/' + relPath;
if (isBundle)
{
final String snapshot = getBundleSnapshot(ovfId);
filePath = createBundleOvfId(filePath, snapshot);
}
return getFileByPath(filePath);
}
/** ######## BOUNDLE RELATED FUNCTIONS ######## */
public String prepareBundle(final String name)
{
final String ovfId = OVF_LOCATION_PREFIX + "bundle/" + name + '/' + name + ".ovf";
TemplateFileSystem.createTemplateFolder(erepoPath, ovfId);
// TODO @apuig must review it
return erId + "/" + getRelativePackagePath(ovfId);
}
public String createBundle(final String ovfId, final String snapshot,
final EnvelopeType envelopeBundle)
{
final String masterOvf = getMasterOVFPackage(ovfId);
final String packagePath = getTemplatePath(erepoPath, ovfId);
// final String originalDiskPath = getDiskFilePath(masterOvf);
final String packageName = getOVFPackageName(masterOvf);
// write the new (bundle) OVF envelope with the file references changes
final String snapshotMark =
createBundleInFolder(packagePath, snapshot, packageName, envelopeBundle);
return codifyBundleOVFId(ovfId, snapshotMark, packageName);
}
private String createBundleInFolder(final String packagePath, final String snapshot,
final String packageName, EnvelopeType envelopeBundle)
{
final String snapshotMark = snapshot + OVF_BUNDLE_PATH_IDENTIFIER;
final String bundlePath = packagePath + snapshotMark + packageName;
File envelopeBundleFile = new File(bundlePath);
if (envelopeBundleFile.exists())
{
throw new AMException(AMError.TEMPLATE_SNAPSHOT_ALREADY_EXIST, bundlePath);
}
FileOutputStream bundleEnvelopeStream = null;
try
{
envelopeBundleFile.createNewFile();
bundleEnvelopeStream = new FileOutputStream(envelopeBundleFile);
}
catch (Exception e1)
{
throw new AMException(AMError.TEMPLATE_SNAPSHOT_ALREADY_EXIST, bundlePath);
}
envelopeBundle =
TemplateToOVFEnvelope.fixFilePathsAndSize(envelopeBundle, snapshot, packagePath);
try
{
OVFSerializer.getInstance().writeXML(envelopeBundle, bundleEnvelopeStream);
}
catch (XMLException e)
{
throw new AMException(AMError.TEMPLATE_SNAPSHOT_CREATE, bundlePath, e);
}
finally
{
try
{
bundleEnvelopeStream.close();
}
catch (IOException e)
{
final String cause = String.format("Can not close the stream to [%s]", bundlePath);
LOG.error(cause);
}
}// close envelope write stream
return snapshotMark;
}
private void deleteBundle(final String ovfId)
{
TemplateFileSystem.deleteBundle(erepoPath, ovfId);
}
/** Imported bundles do not use the ''enterpriserepopath'' */
private void deleteImportedBundle(final String ovfId)
{
TemplateFileSystem.deleteImportedBundle(BASE_REPO_PATH, ovfId);
}
/** ######## REPOSITORY FILESYSTEM USAGE INFO ######## */
public Long getUsedMb()
{
return EnterpriseRepositoryFileSystem.getUsedMb(erepoPath);
}
public TemplateStateDto getTemplateStatus(final String ovfId)
{
return TemplateFileSystem.getTemplateStatus(erepoPath, ovfId);
}
public boolean isEnoughtSpaceOn(final Long expected)
{
return EnterpriseRepositoryFileSystem.isEnoughtSpaceOn(erepoPath, expected);
}
}