org.artifactory.api.module.ModuleInfoUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.artifactory.api.module.ModuleInfoUtils.java

Source

/*
 * Artifactory is a binaries repository manager.
 * Copyright (C) 2012 JFrog Ltd.
 *
 * Artifactory 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, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Artifactory 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 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Artifactory.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.artifactory.api.module;

import com.google.common.collect.Sets;
import org.apache.commons.lang.StringUtils;
import org.artifactory.api.module.regex.NamedMatcher;
import org.artifactory.api.module.regex.NamedPattern;
import org.artifactory.descriptor.repo.RepoLayout;
import org.artifactory.util.PathUtils;
import org.artifactory.util.RepoLayoutUtils;
import org.artifactory.util.layouts.token.BaseTokenFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Set;

/**
 * @author Noam Y. Tenne
 */
public abstract class ModuleInfoUtils {

    private static final Logger log = LoggerFactory.getLogger(ModuleInfoUtils.class);

    private ModuleInfoUtils() {
    }

    public static String constructArtifactPath(ModuleInfo moduleInfo, RepoLayout repoLayout) {
        return constructArtifactPath(moduleInfo, repoLayout, true);
    }

    public static String constructArtifactPath(ModuleInfo moduleInfo, RepoLayout repoLayout,
            boolean clearUnReplacedOptionals) {
        return constructItemPath(moduleInfo, repoLayout, false, clearUnReplacedOptionals);
    }

    public static String constructDescriptorPath(ModuleInfo moduleInfo, RepoLayout repoLayout,
            boolean clearUnReplacedOptionals) {
        return constructItemPath(moduleInfo, repoLayout, true, clearUnReplacedOptionals);
    }

    /**
     * Creates a module info object from an <b>artifact</b> path.<br/>
     * <b>NOTE:</b> Unless you've got a really good reason, refrain from using this method directly. Please create a
     * module info using the methods of {@link org.artifactory.repo.Repo} or {@link org.artifactory.api.repo.RepositoryService}
     *
     * @param itemPath   Artifact path (relative to the repository)
     * @param repoLayout Repository layout to use for resolution
     * @return Module info object. When supplied with a path that does not match the layout, validity is unwarranted.
     */
    public static ModuleInfo moduleInfoFromArtifactPath(String itemPath, RepoLayout repoLayout) {
        return moduleInfoFromItemPath(itemPath, repoLayout, false, false);
    }

    public static ModuleInfo moduleInfoFromArtifactPath(String itemPath, RepoLayout repoLayout,
            boolean supportVersionsTokens) {
        ModuleInfo moduleInfo = null;
        if (repoLayout.isDistinctiveDescriptorPathPattern()) {
            moduleInfo = moduleInfoFromItemPath(itemPath, repoLayout, true, supportVersionsTokens);
            if (moduleInfo.isValid() && StringUtils.isBlank(moduleInfo.getExt())) {
                moduleInfo = new ModuleInfoBuilder(moduleInfo).ext(PathUtils.getExtension(itemPath)).build();
            }
        }

        if ((moduleInfo == null) || !moduleInfo.isValid()) {
            moduleInfo = moduleInfoFromItemPath(itemPath, repoLayout, false, supportVersionsTokens);
        }

        return moduleInfo;
    }

    /**
     * Creates a module info object from a <b>descriptor</b> path.<br/>
     * <b>NOTE:</b> Unless you've got a really good reason, refrain from using this method directly. Please create a
     * module info using the methods of {@link org.artifactory.repo.Repo} or {@link org.artifactory.api.repo.RepositoryService}
     *
     * @param itemPath   Descriptor path (relative to the repository)
     * @param repoLayout Repository layout to use for resolution
     * @return Module info object. When supplied with a path that does not match the layout, validity is unwarranted.
     */
    public static ModuleInfo moduleInfoFromDescriptorPath(String itemPath, RepoLayout repoLayout) {
        ModuleInfo moduleInfo = moduleInfoFromItemPath(itemPath, repoLayout, true, false);
        if (repoLayout.isDistinctiveDescriptorPathPattern() && moduleInfo.isValid()
                && StringUtils.isBlank(moduleInfo.getExt())) {
            return new ModuleInfoBuilder(moduleInfo).ext(PathUtils.getExtension(itemPath)).build();
        }
        return moduleInfo;
    }

    private static String constructItemPath(ModuleInfo moduleInfo, RepoLayout repoLayout, boolean descriptor,
            boolean clearUnReplacedOptionals) {
        if (moduleInfo == null) {
            throw new IllegalArgumentException("Unable to construct a path from a null module info object.");
        }
        if (!moduleInfo.isValid()) {
            throw new IllegalArgumentException("Unable to construct a path from an invalid module info object.");
        }
        if (repoLayout == null) {
            throw new IllegalArgumentException("Unable to construct a path from a null repository layout.");
        }

        String itemPathPattern;
        if (descriptor && repoLayout.isDistinctiveDescriptorPathPattern()) {
            itemPathPattern = repoLayout.getDescriptorPathPattern();
        } else {
            itemPathPattern = repoLayout.getArtifactPathPattern();
        }

        itemPathPattern = replaceDeclaredFields(moduleInfo, itemPathPattern);

        itemPathPattern = RepoLayoutUtils.removeReplacedTokenOptionalBrackets(itemPathPattern, false);

        if (clearUnReplacedOptionals) {
            itemPathPattern = RepoLayoutUtils.removeUnReplacedTokenOptionalBrackets(itemPathPattern);
        }

        return itemPathPattern;
    }

    /**
     * Constructs a path according to a given {@link ModuleInfo} information and a specific repo layout
     * This path can be used as a repoPath for searching artifacts
     *
     * @param moduleInfo the {@link ModuleInfo} information, it must contains at least groupId and artifactId
     * @param repoLayout the {@link RepoLayout} to base the path on
     * @return String path of the gathered information, null in case the given {@link RepoLayout} is invalid,
     *         an invalid repo layout is one that has brackets between the groupId and the moduleId or a bracket before them
     */
    public static String constructBaseItemPath(ModuleInfo moduleInfo, RepoLayout repoLayout) {
        if (moduleInfo == null) {
            throw new IllegalArgumentException("Unable to construct a path from a null module info object.");
        }
        if (repoLayout == null) {
            throw new IllegalArgumentException("Unable to construct a path from a null repository layout.");
        }

        String itemPathPattern = repoLayout.getArtifactPathPattern();
        itemPathPattern = replaceDeclaredFields(moduleInfo, itemPathPattern);
        itemPathPattern = RepoLayoutUtils.removeUnReplacedTokenOptionalBrackets(itemPathPattern);
        itemPathPattern = verifyAndBuildPathPattern(itemPathPattern);
        if (StringUtils.isBlank(itemPathPattern)) {
            log.warn("The repo layout '{}' is invalid and cannot be parsed for searching versions.",
                    repoLayout.getName());
        }

        return itemPathPattern;
    }

    /**
     * Constructs a module version according to the given {@link ModuleInfo} details and the {@link RepoLayout}
     * Examples: '1.4.1-20120319.160615-2', '1.0-SNAPSHOT', '1.2'
     *
     * @param moduleInfo Contains the module details (base revision, file integration revision..)
     * @param repoLayout The repo layout to calculate the module version from
     * @return A module version string
     */
    public static String constructModuleVersion(ModuleInfo moduleInfo, RepoLayout repoLayout) {
        if (moduleInfo == null) {
            throw new IllegalArgumentException("Unable to construct a path from a null module info object.");
        }
        if (repoLayout == null) {
            throw new IllegalArgumentException("Unable to construct a path from a null repository layout.");
        }

        String itemPathPattern = repoLayout.getArtifactPathPattern();
        itemPathPattern = getModuleVersionPattern(itemPathPattern);
        if (!StringUtils.isBlank(itemPathPattern)) {
            itemPathPattern = replaceDeclaredFields(moduleInfo, itemPathPattern);
            itemPathPattern = RepoLayoutUtils.removeReplacedTokenOptionalBrackets(itemPathPattern, false);
            itemPathPattern = RepoLayoutUtils.removeUnReplacedTokenOptionalBrackets(itemPathPattern);
        } else {
            log.warn("The repo layout '{}' is invalid and cannot be parsed for version file name",
                    repoLayout.getName());
        }

        return itemPathPattern;
    }

    /**
     * Constructs the module version pattern, starting from [baseRev] to [fileItegRev]
     *
     * @param itemPathPattern the item path containing all the tokens of a given repo layout
     * @return the tokens path representing the file name, empty string ("") in case of unsupported layout,
     *         Unsupported layout is one which [fileItegRev] is before [baseRev]
     */
    private static String getModuleVersionPattern(String itemPathPattern) {
        String wrappedBaseRevisionToken = RepoLayoutUtils.wrapKeywordAsToken(RepoLayoutUtils.BASE_REVISION);
        String wrappedFileItegRevToken = RepoLayoutUtils
                .wrapKeywordAsToken(RepoLayoutUtils.FILE_INTEGRATION_REVISION);
        int baseRevStartPos = StringUtils.lastIndexOf(itemPathPattern, wrappedBaseRevisionToken);
        int fileItegRevEndPos = StringUtils.lastIndexOf(itemPathPattern, wrappedFileItegRevToken);
        int indexOfClosingOptionalBracket = StringUtils.indexOf(itemPathPattern, ")", fileItegRevEndPos);
        if (indexOfClosingOptionalBracket > 0) {
            fileItegRevEndPos = indexOfClosingOptionalBracket + 1;
        }
        if (fileItegRevEndPos >= baseRevStartPos) {
            return StringUtils.substring(itemPathPattern, baseRevStartPos, fileItegRevEndPos);
        }

        return "";
    }

    /**
     * Verifies the given path is legit and removes the remaining brackets from it
     *
     * @param itemPathPattern the item path to verify
     * @return the repo path without any brackets tokens in it, null in case the repo path is invalid
     *         an invalid repo path is one that has brackets between the groupId and the moduleId or a bracket before them
     */
    private static String verifyAndBuildPathPattern(String itemPathPattern) {
        String[] tokens = StringUtils.split(itemPathPattern, "/");
        StringBuilder newPathBuilder = new StringBuilder();
        boolean foundBracketToken = false;
        for (String token : tokens) {
            if (StringUtils.containsNone(token, new char[] { '[', ']' })) {
                if (foundBracketToken) {
                    // Invalid repo path, found a bracket between the groupId and the moduleId
                    // or a bracket before them, returning null
                    return null;
                }
                newPathBuilder.append(token).append("/");
                foundBracketToken = false;
            } else {
                foundBracketToken = true;
            }
        }

        return newPathBuilder.toString();
    }

    /**
     * Insert all the given module info values to the pattern
     *
     * @param moduleInfo       Module info to use
     * @param itemPathTemplate Item path template to fill
     * @return Modified item path template
     */
    private static String replaceDeclaredFields(ModuleInfo moduleInfo, String itemPathTemplate) {
        Set<String> tokens = Sets.newHashSet(RepoLayoutUtils.TOKENS);
        Map<String, String> customFields = moduleInfo.getCustomFields();
        if (customFields != null) {
            itemPathTemplate = RepoLayoutUtils.clearCustomTokenRegEx(itemPathTemplate);
            tokens.addAll(customFields.keySet());
        }

        for (String token : tokens) {
            String wrappedToken = RepoLayoutUtils.wrapKeywordAsToken(token);

            if (StringUtils.contains(itemPathTemplate, wrappedToken)) {

                String tokenValue = getTokenValue(moduleInfo, token);

                if (RepoLayoutUtils.TYPE.equals(token) && StringUtils.isBlank(tokenValue)) {
                    tokenValue = moduleInfo.getExt();
                }

                if (StringUtils.isNotBlank(tokenValue)) {

                    if (RepoLayoutUtils.tokenHasFilter(token)) {
                        BaseTokenFilter tokenFilter = RepoLayoutUtils.TOKEN_FILTERS.get(token);
                        if (tokenFilter != null) {
                            tokenValue = tokenFilter.forPath(tokenValue);
                        }
                    }

                    itemPathTemplate = StringUtils.replace(itemPathTemplate, wrappedToken, tokenValue);
                }
            }
        }
        return itemPathTemplate;
    }

    private static String getTokenValue(ModuleInfo moduleInfo, String tokenName) {
        if (RepoLayoutUtils.ORGANIZATION.equals(tokenName)) {
            return moduleInfo.getOrganization();
        } else if (RepoLayoutUtils.ORGANIZATION_PATH.equals(tokenName)) {
            return moduleInfo.getOrganization();
        } else if (RepoLayoutUtils.MODULE.equals(tokenName)) {
            return moduleInfo.getModule();
        } else if (RepoLayoutUtils.BASE_REVISION.equals(tokenName)) {
            return moduleInfo.getBaseRevision();
        } else if (RepoLayoutUtils.FOLDER_INTEGRATION_REVISION.equals(tokenName)) {
            return moduleInfo.getFolderIntegrationRevision();
        } else if (RepoLayoutUtils.FILE_INTEGRATION_REVISION.equals(tokenName)) {
            return moduleInfo.getFileIntegrationRevision();
        } else if (RepoLayoutUtils.CLASSIFIER.equals(tokenName)) {
            return moduleInfo.getClassifier();
        } else if (RepoLayoutUtils.EXT.equals(tokenName)) {
            return moduleInfo.getExt();
        } else if (RepoLayoutUtils.TYPE.equals(tokenName)) {
            return moduleInfo.getType();
        } else {
            return moduleInfo.getCustomField(tokenName);
        }
    }

    private static ModuleInfo moduleInfoFromItemPath(String itemPath, RepoLayout repoLayout, boolean descriptor,
            boolean supportVersionsTokens) {
        if (StringUtils.isBlank(itemPath)) {
            throw new IllegalArgumentException("Cannot construct a module info object from a blank item path.");
        }
        if (repoLayout == null) {
            throw new IllegalArgumentException(
                    "Cannot construct a module info object from a null repository layout.");
        }

        String pattern;
        if (descriptor && repoLayout.isDistinctiveDescriptorPathPattern()) {
            pattern = repoLayout.getDescriptorPathPattern();
        } else {
            pattern = repoLayout.getArtifactPathPattern();
        }

        return moduleInfoFromPattern(itemPath, repoLayout, pattern, supportVersionsTokens);
    }

    private static ModuleInfo moduleInfoFromPattern(String itemPath, RepoLayout repoLayout, String pattern,
            boolean supportVersionsTokens) {
        String itemPathPatternRegExp = RepoLayoutUtils.generateRegExpFromPattern(repoLayout, pattern, false,
                supportVersionsTokens);
        //TODO: [by yl] Cache the patterns
        NamedPattern itemPathRegExPattern = NamedPattern.compile(itemPathPatternRegExp);
        NamedMatcher itemPathMatcher = itemPathRegExPattern.matcher(itemPath);
        ModuleInfo moduleInfo;
        if (!itemPathMatcher.matches()) {
            moduleInfo = new ModuleInfo();
        } else {
            moduleInfo = createModuleInfo(itemPathMatcher);
        }
        if (!moduleInfo.isValid()) {
            log.debug("Could not transform {} to a valid module info.", itemPath);
        }
        return moduleInfo;
    }

    private static ModuleInfo createModuleInfo(NamedMatcher itemPathMatcher) {
        Map<String, String> namedGroups = itemPathMatcher.namedGroups();
        ModuleInfoBuilder moduleInfoBuilder = new ModuleInfoBuilder();
        for (Map.Entry<String, String> namedGroupEntry : namedGroups.entrySet()) {
            String groupName = namedGroupEntry.getKey();
            String groupValue = namedGroupEntry.getValue();

            /**
             * Check if the group name (token name) has a filter registered to it before checking for token aliases
             * since the filter might be registered to the alias
             */
            if (RepoLayoutUtils.tokenHasFilter(groupName)) {
                BaseTokenFilter tokenFilter = RepoLayoutUtils.TOKEN_FILTERS.get(groupName);
                if (tokenFilter != null) {
                    groupValue = tokenFilter.fromPath(groupValue);
                }
            }
            setTokenValue(moduleInfoBuilder, groupName, groupValue);
        }

        return moduleInfoBuilder.build();
    }

    private static void setTokenValue(ModuleInfoBuilder moduleInfoBuilder, String tokenName, String tokenValue) {
        if (RepoLayoutUtils.ORGANIZATION.equals(tokenName)) {
            moduleInfoBuilder.organization(tokenValue);
        } else if (RepoLayoutUtils.ORGANIZATION_PATH.equals(tokenName)) {
            moduleInfoBuilder.organization(tokenValue);
        } else if (RepoLayoutUtils.MODULE.equals(tokenName)) {
            moduleInfoBuilder.module(tokenValue);
        } else if (RepoLayoutUtils.BASE_REVISION.equals(tokenName)) {
            moduleInfoBuilder.baseRevision(tokenValue);
        } else if (RepoLayoutUtils.FOLDER_INTEGRATION_REVISION.equals(tokenName)) {
            moduleInfoBuilder.folderIntegrationRevision(tokenValue);
        } else if (RepoLayoutUtils.FILE_INTEGRATION_REVISION.equals(tokenName)) {
            moduleInfoBuilder.fileIntegrationRevision(tokenValue);
        } else if (RepoLayoutUtils.CLASSIFIER.equals(tokenName)) {
            moduleInfoBuilder.classifier(tokenValue);
        } else if (RepoLayoutUtils.EXT.equals(tokenName)) {
            moduleInfoBuilder.ext(tokenValue);
        } else if (RepoLayoutUtils.TYPE.equals(tokenName)) {
            moduleInfoBuilder.type(tokenValue);
        } else {
            moduleInfoBuilder.customField(tokenName, tokenValue);
        }
    }
}