org.apache.ambari.server.stack.StackDirectory.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ambari.server.stack.StackDirectory.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.ambari.server.stack;

import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.state.stack.*;
import org.apache.commons.io.FilenameUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.bind.JAXBException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * Encapsulates IO operations on a stack definition stack directory.
 */
//todo: Normalize all path return values.
//todo: Currently some are relative and some are absolute.
//todo: Current values were dictated by the StackInfo expectations.
public class StackDirectory extends StackDefinitionDirectory {
    /**
     * hooks directory path
     */
    private String hooksDir;

    /**
     * upgrades directory path
     */
    private String upgradesDir;

    /**
     * rco file path
     */
    private String rcoFilePath;

    /**
     * service port file path
     */
    private String spFilePath;

    /**
     * kerberos descriptor file path
     */
    private String kerberosDescriptorFilePath;

    /**
     * repository file
     */
    private RepositoryXml repoFile;

    /**
     * role command order
     */
    private StackRoleCommandOrder roleCommandOrder;

    private StackServicePort servicePort;

    /**
     * repository directory
     */
    private String repoDir;

    /**
     * collection of service directories
     */
    private Collection<ServiceDirectory> serviceDirectories;

    /**
     * map of upgrade pack name to upgrade pack
     */
    //todo: should be a collection but upgrade pack doesn't have a name attribute
    private Map<String, UpgradePack> upgradePacks;

    /**
     * metainfo file representation
     */
    private StackMetainfoXml metaInfoXml;

    /**
     * file unmarshaller
     */
    ModuleFileUnmarshaller unmarshaller = new ModuleFileUnmarshaller();

    /**
     * name of the hooks directory
     */
    public static final String HOOKS_FOLDER_NAME = "hooks";

    /**
     * repository directory name
     */
    private final static String REPOSITORY_FOLDER_NAME = "repos";

    /**
     * repository file name
     */
    private final static String REPOSITORY_FILE_NAME = "repoinfo.xml";

    /**
     * metainfo file name
     */
    private static final String STACK_METAINFO_FILE_NAME = "metainfo.xml";

    /**
     * upgrades directory name
     */
    private static final String UPGRADE_PACK_FOLDER_NAME = "upgrades";

    /**
     * role command order file name
     */
    private static final String ROLE_COMMAND_ORDER_FILE = "role_command_order.json";

    /**
     * logger instance
     */
    private final static Logger LOG = LoggerFactory.getLogger(StackDirectory.class);

    /**
     * Constructor.
     *
     * @param directory  stack directory
     * @throws AmbariException if unable to parse the stack directory
     */
    public StackDirectory(String directory) throws AmbariException {
        super(directory);
        parsePath();
    }

    /**
     * Obtain the stack directory name.
     *
     * @return stack directory name
     */
    public String getStackDirName() {
        return getDirectory().getParentFile().getName();
    }

    /**
     * Obtain the hooks directory path.
     *
     * @return hooks directory path
     */
    public String getHooksDir() {
        return hooksDir;
    }

    /**
     * Obtain the upgrades directory path.
     *
     * @return upgrades directory path
     */
    public String getUpgradesDir() {
        return upgradesDir;
    }

    /**
     * Obtain the rco file path.
     *
     * @return rco file path
     */
    public String getRcoFilePath() {
        return rcoFilePath;
    }

    /**
     * Obtain the path to the (stack-level) Kerberos descriptor file
     *
     * @return the path to the (stack-level) Kerberos descriptor file
     */
    public String getKerberosDescriptorFilePath() {
        return kerberosDescriptorFilePath;
    }

    /**
     * Obtain the repository directory path.
     *
     * @return repository directory path
     */
    public String getRepoDir() {
        return repoDir;
    }

    /**
     * Obtain the repository file object representation.
     *
     * @return repository file object representation
     */
    public RepositoryXml getRepoFile() {
        return repoFile;
    }

    /**
     * Obtain the object representation of the stack metainfo.xml file.
     *
     * @return object representation of the stack metainfo.xml file
     */
    public StackMetainfoXml getMetaInfoFile() {
        return metaInfoXml;
    }

    /**
     * Obtain a collection of all service directories.
     *
     * @return collection of all service directories
     */
    public Collection<ServiceDirectory> getServiceDirectories() {
        return serviceDirectories;
    }

    /**
     * Obtain a map of all upgrade packs.
     *
     * @return map of upgrade pack name to upgrade pack or null if no packs available
     */
    public Map<String, UpgradePack> getUpgradePacks() {
        return upgradePacks;
    }

    /**
     * Obtain the object representation of the stack role_command_order.json file
     *
     * @return object representation of the stack role_command_order.json file
     */

    public StackRoleCommandOrder getRoleCommandOrder() {
        return roleCommandOrder;
    }

    public StackServicePort getServicePort() {
        return servicePort;
    }

    /**
     * Parse the stack directory.
     *
     * @throws AmbariException if unable to parse the directory
     */
    private void parsePath() throws AmbariException {
        Collection<String> subDirs = Arrays.asList(directory.list());
        if (subDirs.contains(HOOKS_FOLDER_NAME)) {
            // hooksDir is expected to be relative to stack root
            hooksDir = getStackDirName() + File.separator + getName() + File.separator + HOOKS_FOLDER_NAME;
        } else {
            LOG.debug("Hooks folder " + getAbsolutePath() + File.separator + HOOKS_FOLDER_NAME + " does not exist");
        }

        if (subDirs.contains(AmbariMetaInfo.RCO_FILE_NAME)) {
            // rcoFile is expected to be absolute
            rcoFilePath = getAbsolutePath() + File.separator + AmbariMetaInfo.RCO_FILE_NAME;
        }

        if (subDirs.contains(AmbariMetaInfo.SP_FILE_NAME)) {
            // rcoFile is expected to be absolute
            spFilePath = getAbsolutePath() + File.separator + AmbariMetaInfo.SP_FILE_NAME;
        }

        if (subDirs.contains(AmbariMetaInfo.KERBEROS_DESCRIPTOR_FILE_NAME)) {
            // kerberosDescriptorFilePath is expected to be absolute
            kerberosDescriptorFilePath = getAbsolutePath() + File.separator
                    + AmbariMetaInfo.KERBEROS_DESCRIPTOR_FILE_NAME;
        }

        parseUpgradePacks(subDirs);
        parseServiceDirectories(subDirs);
        parseRepoFile(subDirs);
        parseMetaInfoFile();
        parseRoleCommandOrder();
        parseServicePort();
    }

    /**
     * Parse the repository file.
     *
     * @param subDirs stack directory sub directories
     * @throws AmbariException if unable to parse the repository file
     */
    private void parseRepoFile(Collection<String> subDirs) throws AmbariException {
        File repositoryFile;

        if (subDirs.contains(REPOSITORY_FOLDER_NAME)) {
            repoDir = getAbsolutePath() + File.separator + REPOSITORY_FOLDER_NAME;
            repositoryFile = new File(
                    getPath() + File.separator + REPOSITORY_FOLDER_NAME + File.separator + REPOSITORY_FILE_NAME);

            if (repositoryFile.exists()) {
                try {
                    repoFile = unmarshaller.unmarshal(RepositoryXml.class, repositoryFile);
                } catch (JAXBException e) {
                    repoFile = new RepositoryXml();
                    repoFile.setValid(false);
                    repoFile.setErrors(
                            "Unable to parse repo file at location: " + repositoryFile.getAbsolutePath());
                }
            }
        }

        if (repoFile == null || !repoFile.isValid()) {
            LOG.warn("No repository information defined for " + ", stackName=" + getStackDirName()
                    + ", stackVersion=" + getPath() + ", repoFolder=" + getPath() + File.separator
                    + REPOSITORY_FOLDER_NAME);
        }
    }

    /**
     * Parse the stack metainfo file.
     *
     * @throws AmbariException if unable to parse the stack metainfo file
     */
    private void parseMetaInfoFile() throws AmbariException {
        File stackMetaInfoFile = new File(getAbsolutePath() + File.separator + STACK_METAINFO_FILE_NAME);

        //todo: is it ok for this file not to exist?
        if (stackMetaInfoFile.exists()) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Reading stack version metainfo from file " + stackMetaInfoFile.getAbsolutePath());
            }

            try {
                metaInfoXml = unmarshaller.unmarshal(StackMetainfoXml.class, stackMetaInfoFile);
            } catch (JAXBException e) {
                metaInfoXml = new StackMetainfoXml();
                metaInfoXml.setValid(false);
                metaInfoXml.setErrors("Unable to parse stack metainfo.xml file at location: "
                        + stackMetaInfoFile.getAbsolutePath());
            }
        }
    }

    /**
     * Parse the stacks service directories.
     *
     * @param subDirs  stack sub directories
     * @throws AmbariException  if unable to parse the service directories
     */
    private void parseServiceDirectories(Collection<String> subDirs) throws AmbariException {
        Collection<ServiceDirectory> dirs = new HashSet<ServiceDirectory>();

        if (subDirs.contains(ServiceDirectory.SERVICES_FOLDER_NAME)) {
            String servicesDir = getAbsolutePath() + File.separator + ServiceDirectory.SERVICES_FOLDER_NAME;
            File baseServiceDir = new File(servicesDir);
            File[] serviceFolders = baseServiceDir.listFiles(AmbariMetaInfo.FILENAME_FILTER);
            if (serviceFolders != null) {
                for (File d : serviceFolders) {
                    if (d.isDirectory()) {
                        try {
                            dirs.add(new StackServiceDirectory(d.getAbsolutePath()));
                        } catch (AmbariException e) {
                            //todo: this seems as though we should propagate this exception
                            //todo: eating it now to keep backwards compatibility
                            LOG.warn(String.format(
                                    "Unable to parse stack definition service at '%s'.  Ignoring service. : %s",
                                    d.getAbsolutePath(), e.toString()));
                        }
                    }
                }
            }
        }

        if (dirs.isEmpty()) {
            //todo: what does it mean for a stack to have no services?
            LOG.info("The stack defined at '" + getAbsolutePath() + "' contains no services");
        }
        serviceDirectories = dirs;
    }

    /**
     * Parse all stack upgrade files for the stack.
     *
     * @param subDirs  stack sub directories
     * @throws AmbariException if unable to parse stack upgrade file
     */
    private void parseUpgradePacks(Collection<String> subDirs) throws AmbariException {
        Map<String, UpgradePack> upgradeMap = new HashMap<String, UpgradePack>();
        if (subDirs.contains(UPGRADE_PACK_FOLDER_NAME)) {
            File f = new File(getAbsolutePath() + File.separator + UPGRADE_PACK_FOLDER_NAME);
            if (f.isDirectory()) {
                upgradesDir = f.getAbsolutePath();
                for (File upgradeFile : f.listFiles(XML_FILENAME_FILTER)) {
                    try {
                        upgradeMap.put(FilenameUtils.removeExtension(upgradeFile.getName()),
                                unmarshaller.unmarshal(UpgradePack.class, upgradeFile));
                    } catch (JAXBException e) {
                        throw new AmbariException(
                                "Unable to parse stack upgrade file at location: " + upgradeFile.getAbsolutePath(),
                                e);
                    }
                }
            }
        }

        if (upgradesDir == null) {
            LOG.info("Stack '{}' doesn't contain an upgrade directory ", getPath());
        }

        if (!upgradeMap.isEmpty()) {
            upgradePacks = upgradeMap;
        }
    }

    /**
     * Parse role command order file
     */

    private void parseRoleCommandOrder() {
        HashMap<String, Object> result = null;
        ObjectMapper mapper = new ObjectMapper();
        try {
            TypeReference<Map<String, Object>> rcoElementTypeReference = new TypeReference<Map<String, Object>>() {
            };
            if (rcoFilePath != null) {
                File file = new File(rcoFilePath);
                result = mapper.readValue(file, rcoElementTypeReference);
                LOG.info("Role command order info was loaded from file: {}", file.getAbsolutePath());
            } else {
                InputStream rcoInputStream = ClassLoader.getSystemResourceAsStream(ROLE_COMMAND_ORDER_FILE);
                result = mapper.readValue(rcoInputStream, rcoElementTypeReference);
                LOG.info("Role command order info was loaded from classpath: "
                        + ClassLoader.getSystemResource(ROLE_COMMAND_ORDER_FILE));
            }
            roleCommandOrder = new StackRoleCommandOrder(result);
        } catch (IOException e) {
            LOG.error(String.format("Can not read role command order info %s", rcoFilePath), e);
        }
    }

    private void parseServicePort() {
        Map<String, Map<String, List<String>>> result = null;
        ObjectMapper mapper = new ObjectMapper();
        try {
            TypeReference<Map<String, Map<String, List<String>>>> spElementTypeReference = new TypeReference<Map<String, Map<String, List<String>>>>() {
            };
            if (spFilePath != null) {
                File file = new File(spFilePath);
                result = mapper.readValue(file, spElementTypeReference);
                LOG.info("Service port info was loaded from file: {}", file.getAbsolutePath());
            } else {
                InputStream spInputStream = ClassLoader.getSystemResourceAsStream(AmbariMetaInfo.SP_FILE_NAME);
                if (spInputStream != null) {
                    result = mapper.readValue(spInputStream, spElementTypeReference);
                    LOG.info("Service port info was loaded from classpath: "
                            + ClassLoader.getSystemResource(AmbariMetaInfo.SP_FILE_NAME));
                }
            }
            servicePort = new StackServicePort(result);
        } catch (IOException e) {
            LOG.error(String.format("Can not read service port info %s", spFilePath), e);
        }

    }
}