Java tutorial
/* * 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; } }