org.cloudifysource.shell.commands.AddTemplates.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudifysource.shell.commands.AddTemplates.java

Source

/*******************************************************************************
 * Copyright (c) 2012 GigaSpaces Technologies Ltd. All rights reserved
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *******************************************************************************/
package org.cloudifysource.shell.commands;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
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 org.apache.commons.lang.StringUtils;
import org.apache.felix.gogo.commands.Argument;
import org.apache.felix.gogo.commands.Command;
import org.cloudifysource.domain.ComputeTemplateHolder;
import org.cloudifysource.dsl.internal.CloudifyConstants;
import org.cloudifysource.dsl.internal.CloudifyErrorMessages;
import org.cloudifysource.dsl.internal.DSLReader;
import org.cloudifysource.dsl.internal.DSLUtils;
import org.cloudifysource.dsl.internal.packaging.Packager;
import org.cloudifysource.dsl.rest.AddTemplatesException;
import org.cloudifysource.dsl.rest.request.AddTemplatesRequest;
import org.cloudifysource.dsl.rest.response.AddTemplateResponse;
import org.cloudifysource.dsl.rest.response.AddTemplatesResponse;
import org.cloudifysource.dsl.rest.response.AddTemplatesStatus;
import org.cloudifysource.restclient.RestClient;
import org.cloudifysource.shell.ShellUtils;
import org.cloudifysource.shell.exceptions.CLIStatusException;
import org.cloudifysource.shell.installer.CLIEventsDisplayer;
import org.cloudifysource.shell.rest.RestAdminFacade;
import org.cloudifysource.utilitydomain.data.reader.ComputeTemplatesReader;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.ObjectMapper;
import org.fusesource.jansi.Ansi.Color;

/**
 * Adds templates to be included in the cloud's templates list. Reads the templates from the (groovy) templates-file.
 * 
 * Required arguments: templates-file-or-folder - Path to a single groovy file (one template to add) or to a folder
 * (zipped or not) contains one or more groovy files each groovy file has the form of "*-template.groovy" and declare
 * one template to add.
 * 
 * Command syntax: add-templates templates-file-or-folder
 * 
 * @author yael
 * 
 * @since 2.3.0
 * 
 */
@Command(scope = "cloudify", name = "add-templates", description = "Adds templates to the cloud")
public class AddTemplates extends AdminAwareCommand implements NewRestClientCommand {

    @Argument(required = true, name = "templates-file-or-folder", description = "A template file or a templates folder that can contain several template files.")
    private File templatesFileOrDir;

    private final CLIEventsDisplayer displayer = new CLIEventsDisplayer();

    @Override
    protected Object doExecute() throws Exception {

        final String templatesPath = templatesFileOrDir.getAbsolutePath();
        validateTemplateFile(templatesPath);
        final boolean isZipFile = isZipFile(templatesFileOrDir);
        final File templatesFolder = getTemplatesFolder(isZipFile);
        final List<ComputeTemplateHolder> expectedTemplates = new ComputeTemplatesReader()
                .readCloudTemplatesFromDirectory(templatesFolder);
        File zipFile = templatesFileOrDir;
        if (!isZipFile) {
            zipFile = Packager.createZipFile("templates", templatesFolder);
        }
        // add the templates to the cloud
        logger.info("Adding " + expectedTemplates.size() + " templates to cloud.");
        List<String> addedTemplates;
        try {
            addedTemplates = adminFacade.addTemplates(zipFile);
        } catch (final CLIStatusException e) {
            final String reasonCode = e.getReasonCode();
            if (reasonCode.equals(CloudifyErrorMessages.FAILED_TO_ADD_TEMPLATES.getName())
                    || reasonCode.equals(CloudifyErrorMessages.PARTLY_FAILED_TO_ADD_TEMPLATES.getName())) {
                throw new CLIStatusException(reasonCode, convertArgsToIndentJason(e.getArgs()));
            } else if (reasonCode.equals("failed_to_add_all_templates")) {
                if (e.getArgs().length > 0) {
                    throw new CLIStatusException(reasonCode, getIndentMap((Map<String, Object>) e.getArgs()[0]));
                }
            }
            throw e;
        }
        return getFormattedMessage("templates_added_successfully", Color.GREEN)
                + getFormatedAddedTemplateNamesList(addedTemplates);
    }

    private File getTemplatesFolder(final boolean isZipFile) throws IOException, CLIStatusException {
        final String templatesFolderName = templatesFileOrDir.getName();
        if (templatesFileOrDir.isFile()) {
            if (isZipFile) {
                return new ComputeTemplatesReader().unzipCloudTemplatesFolder(templatesFileOrDir);
            }
            // templatesFileOrDir is a groovy file
            if (!templatesFolderName.endsWith(DSLUtils.TEMPLATE_DSL_FILE_NAME_SUFFIX)) {
                throw new CLIStatusException("illegal_template_file_name", templatesFolderName);
            }
            final File parentFile = templatesFileOrDir.getParentFile();
            final File[] actualTemplatesDslFiles = DSLReader
                    .findDefaultDSLFiles(DSLUtils.TEMPLATE_DSL_FILE_NAME_SUFFIX, parentFile);
            if (actualTemplatesDslFiles.length > 1) {
                throw new CLIStatusException("too_many_template_files", Arrays.toString(actualTemplatesDslFiles));
            }
            return parentFile;
        }
        // templatesFileOrDir is a directory
        return templatesFileOrDir;
    }

    private boolean isZipFile(final File templatesFileOrDir) {
        final String templatesFolderName = templatesFileOrDir.getName();
        return templatesFolderName.endsWith(".zip") || templatesFolderName.endsWith(".jar");
    }

    private static Object[] convertArgsToIndentJason(final Object[] args) {
        final String[] newArgs = new String[args.length];
        if (newArgs.length < 2) {
            return args;
        }
        final Map<String, Map<String, String>> failedToAddTemplates = (Map<String, Map<String, String>>) args[0];
        final StringBuilder failedToAddTemplatesStr = new StringBuilder();
        if (failedToAddTemplates.isEmpty()) {
            failedToAddTemplatesStr.append("{ }");
        } else {
            failedToAddTemplatesStr.append(CloudifyConstants.NEW_LINE).append("{")
                    .append(CloudifyConstants.NEW_LINE);
            for (final Entry<String, Map<String, String>> entry : failedToAddTemplates.entrySet()) {
                final Map<String, String> failedToAddTemplatesErrDesc = entry.getValue();
                failedToAddTemplatesStr.append(CloudifyConstants.TAB_CHAR).append(entry.getKey()).append(":")
                        .append(CloudifyConstants.NEW_LINE).append(CloudifyConstants.TAB_CHAR).append("{")
                        .append(CloudifyConstants.NEW_LINE);
                for (final Entry<String, String> templateErrDesc : failedToAddTemplatesErrDesc.entrySet()) {
                    failedToAddTemplatesStr.append(CloudifyConstants.TAB_CHAR).append(CloudifyConstants.TAB_CHAR)
                            .append(templateErrDesc.getKey()).append(" - ").append(templateErrDesc.getValue())
                            .append(CloudifyConstants.NEW_LINE);
                }
                failedToAddTemplatesStr.append(CloudifyConstants.TAB_CHAR).append("}")
                        .append(CloudifyConstants.NEW_LINE);
            }
            failedToAddTemplatesStr.append("}");
        }
        newArgs[0] = failedToAddTemplatesStr.toString();

        newArgs[1] = getIndentMap((Map<String, Object>) args[1]);

        return newArgs;
    }

    private static String getIndentMap(final Map<String, Object> map) {
        final StringBuilder successfullyAddedTemplatesStr = new StringBuilder();
        if (map.isEmpty()) {
            successfullyAddedTemplatesStr.append("{ }");
        } else {
            successfullyAddedTemplatesStr.append(CloudifyConstants.NEW_LINE).append("{")
                    .append(CloudifyConstants.NEW_LINE);
            for (final Entry<String, Object> entry : map.entrySet()) {
                successfullyAddedTemplatesStr.append(CloudifyConstants.TAB_CHAR).append(entry.getKey()).append(": ")
                        .append(entry.getValue()).append(CloudifyConstants.NEW_LINE);
            }
            successfullyAddedTemplatesStr.append("}");
        }
        return successfullyAddedTemplatesStr.toString();
    }

    @Override
    public Object doExecuteNewRestClient() throws Exception {
        final RestClient newRestClient = ((RestAdminFacade) getRestAdminFacade()).getNewRestClient();
        final String templatesPath = templatesFileOrDir.getAbsolutePath();
        validateTemplateFile(templatesPath);
        final boolean isZipFile = isZipFile(templatesFileOrDir);
        final File templatesFolder = getTemplatesFolder(isZipFile);
        final List<ComputeTemplateHolder> expectedTemplates = new ComputeTemplatesReader()
                .readCloudTemplatesFromDirectory(templatesFolder);
        File zipFile = templatesFileOrDir;
        if (!isZipFile) {
            zipFile = Packager.createZipFile("templates", templatesFolder);
        }
        // add the templates to the cloud
        logger.info("Adding " + expectedTemplates.size() + " templates to cloud:"
                + printExpectedTemplates(expectedTemplates));
        final String uploadKey = ShellUtils.uploadToRepo(newRestClient, zipFile, displayer);
        final AddTemplatesRequest request = new AddTemplatesRequest();
        request.setUploadKey(uploadKey);
        try {
            final AddTemplatesResponse response = newRestClient.addTemplates(request);
            return getFormattedMessage("templates_added_successfully", Color.GREEN)
                    + getSuccessfulMessage(response);

        } catch (AddTemplatesException e) {
            // failure or partial failure
            return getFailureMessage(e.getAddTemplatesResponse());
        }
    }

    private static String getIndentJson(final String body) throws IOException {
        if (StringUtils.isBlank(body)) {
            return null;
        }

        StringWriter out = new StringWriter();
        JsonParser parser = null;
        JsonGenerator gen = null;
        try {
            JsonFactory fac = new JsonFactory();

            parser = fac.createJsonParser(new StringReader(body));
            ObjectMapper mapper = new ObjectMapper();
            JsonNode node = mapper.readTree(parser);
            // Create pretty printer:
            gen = fac.createJsonGenerator(out);
            gen.useDefaultPrettyPrinter();
            // Write:
            mapper.writeTree(gen, node);

            gen.close();
            parser.close();

            return out.toString();

        } finally {
            out.close();
            if (gen != null) {
                gen.close();
            }
            if (parser != null) {
                parser.close();
            }
        }
    }

    private static Object getFormatedAddedTemplateNamesList(final List<String> templates) {
        int size = templates.size();
        final StringBuilder sb = new StringBuilder(CloudifyConstants.NEW_LINE).append("The ").append(size)
                .append(" template" + (size == 1 ? "" : "s") + " added:");

        for (final String templateName : templates) {
            sb.append(CloudifyConstants.NEW_LINE).append(CloudifyConstants.TAB_CHAR).append(templateName);
        }
        return sb;
    }

    private String getFailureMessage(final AddTemplatesResponse addTemplatesResponse) throws IOException {
        List<String> instances = addTemplatesResponse.getInstances();
        int size = instances.size();
        StringBuilder sb = new StringBuilder("Add templates to " + size + " REST instance"
                + (size == 1 ? " " : "s ") + instances + " resulted with ");
        if (AddTemplatesStatus.PARTIAL_FAILURE.equals(addTemplatesResponse.getStatus())) {
            sb.append("partial failure (at least one template failed to be added to at least one REST instance):");
        } else {
            sb.append("failure (all templates failed to be added to all REST instances):");
        }
        sb.append(CloudifyConstants.NEW_LINE);

        Map<String, AddTemplateResponse> templates = addTemplatesResponse.getTemplates();
        Map<String, Map<String, String>> resultMap = new HashMap<String, Map<String, String>>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (Entry<String, AddTemplateResponse> entry : templates.entrySet()) {
            AddTemplateResponse addTemplateResponse = entry.getValue();
            Map<String, String> templateResultMap = new HashMap<String, String>();
            templateResultMap.put("failed to add to",
                    objectMapper.writeValueAsString(addTemplateResponse.getFailedToAddHosts()));
            templateResultMap.put("successfully added to",
                    objectMapper.writeValueAsString(addTemplateResponse.getSuccessfullyAddedHosts()));
            resultMap.put(entry.getKey(), templateResultMap);
        }
        sb.append(getIndentJson(objectMapper.writeValueAsString(resultMap)));
        return sb.toString().replaceAll("\"", "").replaceAll("\\\\", "");
    }

    private String getSuccessfulMessage(final AddTemplatesResponse response) {
        StringBuilder sb = new StringBuilder();
        sb.append("Templates were added to all REST instances: ");
        sb.append(response.getInstances());
        Map<String, AddTemplateResponse> templates = response.getTemplates();
        List<String> templateNames = new LinkedList<String>();
        for (String templateName : templates.keySet()) {
            templateNames.add(templateName);
        }
        sb.append(getFormatedAddedTemplateNamesList(templateNames));
        return sb.toString();
    }

    private String printExpectedTemplates(final List<ComputeTemplateHolder> expectedTemplates) {
        final StringBuilder sb = new StringBuilder();
        for (final ComputeTemplateHolder computeTemplateHolder : expectedTemplates) {
            sb.append(CloudifyConstants.NEW_LINE);
            sb.append(computeTemplateHolder.getName());
        }
        return sb.toString();
    }

    private void validateTemplateFile(final String templatesPath) throws CLIStatusException {
        logger.info("Validating template folder and files: " + templatesPath);
        if (!templatesFileOrDir.exists()) {
            throw new CLIStatusException("templates_file_not_found", templatesPath);
        }
    }

}