package org.cloudifysource.utilitydomain.data.reader;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.cloudifysource.domain.ComputeTemplateHolder;
import org.cloudifysource.domain.cloud.Cloud;
import org.cloudifysource.domain.cloud.compute.ComputeTemplate;
import org.cloudifysource.dsl.internal.DSLException;
import org.cloudifysource.dsl.internal.DSLReader;
import org.cloudifysource.dsl.internal.DSLUtils;
import org.cloudifysource.dsl.internal.ServiceReader;
import org.cloudifysource.dsl.internal.packaging.ZipUtils;
/**
* A reader for external cloud templates.
* @author yael
*
*/
public class ComputeTemplatesReader {
private static Logger logger = Logger.getLogger(ComputeTemplatesReader.class.getName());
public ComputeTemplatesReader() {
}
/**
* Unzip the templates folder and validate it is a directory.
* @param zipFile The file to unzip.
* @return The unzipped file.
* @throws IOException If failed to unzip the zipFile.
*/
public File unzipCloudTemplatesFolder(final File zipFile)
throws IOException {
final File unzipFile = ServiceReader.createTempDir("templates");
unzipFile.deleteOnExit();
ZipUtils.unzip(zipFile, unzipFile);
if (unzipFile.isFile()) {
throw new IllegalArgumentException("templates folder is not a folder: " + unzipFile.getAbsolutePath());
}
return unzipFile;
}
/**
*
* @param templatesDir
* The templates directory.
* @return The templates read from the templates files found in templatesDir.
* @throws DSLException If failed to read the DSL template files.
*/
public List<ComputeTemplateHolder> readCloudTemplatesFromDirectory(final File templatesDir)
throws DSLException {
if (!templatesDir.exists()) {
throw new DSLException(templatesDir + " does not exist.");
}
if (!templatesDir.isDirectory()) {
throw new DSLException(templatesDir + " is not a directory.");
}
File[] templateFiles =
DSLReader.findDefaultDSLFiles(DSLUtils.TEMPLATE_DSL_FILE_NAME_SUFFIX, templatesDir);
if (templateFiles == null || templateFiles.length == 0) {
throw new DSLException("There is no template files (files with the suffix "
+ DSLUtils.TEMPLATE_DSL_FILE_NAME_SUFFIX + ") in the given folder [" + templatesDir + "]");
}
Map<String, ComputeTemplateHolder> cloudTemplatesMap = new HashMap<String, ComputeTemplateHolder>();
// for each file - reads the templates from it and creates a suitable CloudTemplateHolder object.
for (File templateFile : templateFiles) {
List<ComputeTemplateHolder> cloudTemplatesFromFile;
try {
cloudTemplatesFromFile = readCloudTemplatesFromFile(templateFile);
} catch (Exception e) {
throw new DSLException("Failed to read template file [" + templateFile.getName()
+ "] from folder [" + templatesDir.getAbsolutePath() + "]. Reason: " + e.getMessage(), e);
}
for (ComputeTemplateHolder cloudTemplateHolder : cloudTemplatesFromFile) {
String name = cloudTemplateHolder.getName();
if (cloudTemplatesMap.containsKey(name)) {
throw new DSLException("Failed to read template file [" + templateFile.getName()
+ "] from folder [" + templatesDir.getAbsolutePath()
+ "]. Reason: template with the name [" + name + "] already exist in folder.");
}
cloudTemplatesMap.put(name, cloudTemplateHolder);
}
}
return new LinkedList<ComputeTemplateHolder>(cloudTemplatesMap.values());
}
/**
*
* @param templateFile
* The template file.
* @return The holder of the CloudTemplate read from the file.
* @throws DSLException If failed to read the DSL template files..
*/
public List<ComputeTemplateHolder> readCloudTemplatesFromFile(final File templateFile)
throws DSLException {
DSLReader dslReader = new DSLReader();
dslReader.setDslFile(templateFile);
dslReader.setCreateServiceContext(false);
@SuppressWarnings("unchecked")
Map<String, ComputeTemplate> cloudTemplateMap = dslReader.readDslEntity(Map.class);
if (cloudTemplateMap.isEmpty()) {
throw new DSLException("The file " + templateFile + " evaluates to an empty map.");
}
int size = cloudTemplateMap.size();
if (size > DSLUtils.MAX_TEMPLATES_PER_FILE) {
throw new DSLException("Too many templates in one groovy file [" + templateFile.getName() + " declares " + size
+ " templates, only " + DSLUtils.MAX_TEMPLATES_PER_FILE + " allowed].");
}
List<ComputeTemplateHolder> cloudTemplateHolders =
new ArrayList<ComputeTemplateHolder>(cloudTemplateMap.size());
for (Entry<String, ComputeTemplate> entry : cloudTemplateMap.entrySet()) {
ComputeTemplateHolder holder = new ComputeTemplateHolder();
holder.setName(entry.getKey());
holder.setCloudTemplate(entry.getValue());
holder.setTemplateFileName(templateFile.getName());
holder.setPropertiesFileName(dslReader.getPropertiesFileName());
File overridesFile = dslReader.getOverridesFile();
if (overridesFile != null) {
holder.setOverridesFileName(overridesFile.getName());
}
cloudTemplateHolders.add(holder);
}
return cloudTemplateHolders;
}
/**
* Add cloud templates from the template files in the folder.
* @param cloud .
* @param templatesFolders .
* @return the added templates.
*/
public List<ComputeTemplate> addAdditionalTemplates(final Cloud cloud, final File[] templatesFolders) {
List<ComputeTemplate> addedTemplates = new LinkedList<ComputeTemplate>();
List<ComputeTemplateHolder> additionalTemplates = null;
// scan all templates folders and add the templates from each folder to the cloud.
for (File folder : templatesFolders) {
logger.log(Level.INFO,
"[addAdditionalTemplates] - Adding templates to cloud from folder " + folder.getAbsolutePath());
logger.info("[addAdditionalTemplates] - Folder's files: " + Arrays.toString(folder.listFiles()));
try {
additionalTemplates = readCloudTemplatesFromDirectory(folder);
// scan holders and add all templates to cloud.
for (ComputeTemplateHolder holder : additionalTemplates) {
String templateName = holder.getName();
Map<String, ComputeTemplate> cloudTemplates = cloud.getCloudCompute().getTemplates();
// not supposed to happen
if (cloudTemplates.containsKey(templateName)) {
logger.log(Level.WARNING, "[addAdditionalTemplates] - template already exist: " + templateName);
continue;
}
// set the local absolute path to the upload directory
ComputeTemplate cloudTemplate = holder.getCloudTemplate();
String uploadAbsolutePath = new File(folder, cloudTemplate.getLocalDirectory()).getAbsolutePath();
cloudTemplate.setAbsoluteUploadDir(uploadAbsolutePath);
// add template to cloud
cloudTemplates.put(templateName, cloudTemplate);
addedTemplates.add(cloudTemplate);
}
} catch (DSLException e) {
logger.log(Level.WARNING, "[addAdditionalTemplates] - Failed to read templates from directory ["
+ folder.getAbsolutePath() + "]. Error: " + e.getMessage());
}
}
return addedTemplates;
}
/**
* Removes template file with a given suffix from templateFolder.
* @param templateFolder .
* @param templateName .
*/
public static void removeTemplateFiles(final File templateFolder, final String templateName) {
String proeprtiesFileName = templateName + DSLUtils.TEMPLATES_PROPERTIES_FILE_NAME_SUFFIX;
File propertiesFile = new File(templateFolder, proeprtiesFileName);
if (propertiesFile.exists()) {
boolean delete = propertiesFile.delete();
logger.log(Level.FINE, "[removeTemplateFiles] - "
+ (delete ? "Successfully deleted" : "Failed to delete")
+ " template's properties file [" + propertiesFile.getAbsolutePath() + "].");
}
String overridesFileName = templateName + DSLUtils.TEMPLATES_OVERRIDES_FILE_NAME_SUFFIX;
File overridesFile = new File(templateFolder, overridesFileName);
if (overridesFile.exists()) {
boolean delete = overridesFile.delete();
logger.log(Level.FINE, "[removeTemplateFiles] - "
+ (delete ? "Successfully deleted" : "Failed to delete")
+ " template's overrides file [" + overridesFile.getAbsolutePath() + "].");
}
}
}