hudson.plugins.jobConfigHistory.ConfigInfoCollector.java Source code

Java tutorial

Introduction

Here is the source code for hudson.plugins.jobConfigHistory.ConfigInfoCollector.java

Source

/*
 * The MIT License
 *
 * Copyright 2013 Mirko Friedenhagen.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package hudson.plugins.jobConfigHistory;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.ArrayUtils;

/**
 * Collects all configs of a special type. For Jobs these follow the pattern:
 * <tt>config-history/jobs/FOLDERNAME/JOBNAME/TIMESTAMP</tt>,
 * where <tt>FOLDERNAME</tt> may be empty.
 *
 * Extracted from {@link JobConfigHistoryRootAction} for easier testability.
 *
 * @author Mirko Friedenhagen.
 */
final class ConfigInfoCollector {

    /**
     * outparameter.
     */
    private final List<ConfigInfo> configs = new ArrayList<ConfigInfo>();

    /**
     * Type to collect.
     */
    private final String type;

    /**
     * HistoryDao.
     */
    private final OverviewHistoryDao overViewhistoryDao;

    /**
     * Collects configs of the given type.
     *
     * @param type may be one of deleted, created or jobs?
     * @param overviewHistoryDao the value of historyDao
     */
    public ConfigInfoCollector(String type, OverviewHistoryDao overviewHistoryDao) {
        this.type = type;
        this.overViewhistoryDao = overviewHistoryDao;
    }

    /**
     * Gets config history entries for the view options 'created', 'deleted' and
     * 'jobs'. While 'jobs' displays all available job config history entries,
     * 'deleted' and 'created' only show the last or the first one respectively.
     *
     * @param itemDir
     *            The job directory as File
     * @param folderName
     *            Something Jesse Glick came up with but never documented, probably the folderName.
     * @throws IOException
     *             If one of the entries cannot be read.
     */
    void getConfigsForType(File itemDir, String folderName) throws IOException {
        final String itemName = folderName.isEmpty() ? itemDir.getName()
                : folderName + "/jobs/" + itemDir.getName();
        final List<HistoryDescr> historyEntries = new ArrayList<HistoryDescr>(
                overViewhistoryDao.getJobHistory(itemName).values());
        if (historyEntries.isEmpty()) {
            return;
        }
        final boolean isADeletedJob = DeletedFileFilter.accepts(itemName);
        final boolean isNotADeletedJob = !isADeletedJob;
        if ("created".equals(type)) {
            if (isADeletedJob) {
                return;
            }
            HistoryDescr histDescr = historyEntries.get(0);
            if ("Created".equals(histDescr.getOperation())) {
                final ConfigInfo config = ConfigInfo.create(itemName, true, histDescr, true);
                configs.add(config);
            } else {
                //Why would the created entry not be the first one? Answer:
                //There's always a 'Changed' entry before the 'Created' entry,
                //because in the Jenkins core, when creating a new job,
                //the SaveableListener (which handles changes) fires
                //before the ItemListener (which handles creation, deletion etc.)
                //Older versions of the plugin didn't show this behaviour
                //since it was masked by some race condition.
                histDescr = historyEntries.get(1);
                if ("Created".equals(histDescr.getOperation())) {
                    final ConfigInfo config = ConfigInfo.create(itemName, true, histDescr, true);
                    configs.add(config);
                }
            }
        } else if ("deleted".equals(type)) {
            final HistoryDescr histDescr = historyEntries.get(historyEntries.size() - 1);
            if ("Deleted".equals(histDescr.getOperation())) {
                final ConfigInfo config = ConfigInfo.create(itemName, false, histDescr, false);
                configs.add(config);
            }
        } else {
            configs.addAll(HistoryDescrToConfigInfo.convert(itemName, true, historyEntries, isNotADeletedJob));
        }
    }

    /**
     * Collects configs.
     *
     * @param folderName
     *            folderName, usually just the empty string.
     * @return List of ConfigInfo, may be empty
     * @throws IOException if an entry could not be read.
     */
    public List<ConfigInfo> collect(final String folderName) throws IOException {
        final File[] itemDirs;
        if ("deleted".equals(type)) {
            itemDirs = overViewhistoryDao.getDeletedJobs(folderName);
        } else {
            itemDirs = (File[]) ArrayUtils.addAll(overViewhistoryDao.getDeletedJobs(folderName),
                    overViewhistoryDao.getJobs(folderName));
        }
        Arrays.sort(itemDirs, FileNameComparator.INSTANCE);
        for (final File itemDir : itemDirs) {
            getConfigsForType(itemDir, folderName);
        }
        return configs;
    }
}