/*
* The MIT License
*
* Copyright 2012 Sony Mobile Communications Inc. All rights reserved.
*
* 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 com.sonyericsson.jenkins.plugins.bfa.db;
import com.sonyericsson.jenkins.plugins.bfa.graphs.FailureCauseTimeInterval;
import com.sonyericsson.jenkins.plugins.bfa.graphs.GraphFilterBuilder;
import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause;
import com.sonyericsson.jenkins.plugins.bfa.statistics.Statistics;
import com.sonyericsson.jenkins.plugins.bfa.utils.ObjectCountPair;
import hudson.ExtensionList;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.model.Run;
import jenkins.model.Jenkins;
import org.jfree.data.time.TimePeriod;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* Base class for storage implementations of {@link FailureCause}s. Extend this class and put <code>@Extension</code> on
* the descriptor to provide your own.
*
* @author Robert Sandell <robert.sandell@sonyericsson.com>
*/
public abstract class KnowledgeBase implements Describable<KnowledgeBase>, Serializable {
private static final long DEFAULT_NBR_OF_NULL_FAILURE_CAUSES = 0;
/**
* Get the list of {@link FailureCause}s. It is intended to be used in the scanning phase hence it should be
* returned as quickly as possible, so the list could be cached.
*
* @return the full list of causes.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
*/
public abstract Collection<FailureCause> getCauses() throws Exception;
/**
* Get the list of the {@link FailureCause}'s names and ids. The list should be the latest possible from the DB as
* they will be used for editing. The objects returned should contain at least the id and the name of the cause.
*
* @return the full list of the names and ids of the causes.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
*/
public abstract Collection<FailureCause> getCauseNames() throws Exception;
/**
* Get a shallow list of the {@link FailureCause}s. The list should be the latest possible from the DB as
* they will be used in the list of causes to edit.
* shallow meaning no indications but information enough to show a nice list; at least id and name but description,
* comment, lastOccurred and categories are preferred as well.
*
* @return a shallow list of all causes.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
* @see #getCauseNames()
*/
public abstract Collection<FailureCause> getShallowCauses() throws Exception;
/**
* Get the cause with the given id. The cause returned is intended to be edited right away, so it should be as fresh
* from the db as possible.
*
* @param id the id of the cause.
* @return the cause or null if a cause with that id could not be found.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
*/
public abstract FailureCause getCause(String id) throws Exception;
/**
* Saves a new cause to the db and generates a new id for the cause.
*
* @param cause the cause to add.
* @return the same cause but with a new id.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
*/
public abstract FailureCause addCause(FailureCause cause) throws Exception;
/**
* Removes the cause from the knowledge base.
*
* @param id the id of the cause to remove.
* @throws Exception if so.
* @return the removed FailureCause.
*/
public abstract FailureCause removeCause(String id) throws Exception;
/**
* Saves a cause to the db. Assumes that the id is kept from when it was fetched. Can also be an existing cause in
* another {@link KnowledgeBase} implementation with a preexisting id that is being converted via {@link
* #convertFrom(KnowledgeBase)}.
*
* @param cause the cause to add.
* @return the same cause but with a new id.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
*/
public abstract FailureCause saveCause(FailureCause cause) throws Exception;
/**
* Converts the existing old knowledge base into this one. Will be called after the creation of a new object when
* then Jenkins config is saved, So it could just be that the old one is exactly the same as this one.
*
* @param oldKnowledgeBase the old one.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
*/
public abstract void convertFrom(KnowledgeBase oldKnowledgeBase) throws Exception;
/**
* Gets the unique categories of all FailureCauses.
* @return the list of categories.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
*/
public abstract List<String> getCategories() throws Exception;
/**
* Does a full copy of the data in the old one to this one. Using the public api, can be used by implementations of
* {@link #convertFrom(KnowledgeBase)} to handle conversion from an unknown source type.
*
* @param oldKnowledgeBase the old one.
* @see #convertFrom(KnowledgeBase)
* @throws Exception if anything goes wrong in the KnowledgeBase handling.
*/
protected void convertFromAbstract(KnowledgeBase oldKnowledgeBase) throws Exception {
for (FailureCause cause : oldKnowledgeBase.getCauseNames()) {
saveCause(oldKnowledgeBase.getCause(cause.getId()));
}
}
/**
* Called to see if the configuration has changed.
*
* @param oldKnowledgeBase the previous config.
* @return true if it is the same.
*/
public abstract boolean equals(KnowledgeBase oldKnowledgeBase);
/**
* Called when the KnowledgeBase should be up and running.
* @throws Exception if anything goes wrong during the startup.
*/
public abstract void start() throws Exception;
/**
* Called when it is time to clean up after the KnowledgeBase.
*/
public abstract void stop();
@Override
public int hashCode() {
//Making checkstyle happy.
return super.hashCode();
}
/**
* If Statistics logging is enabled on this knowledge base or not.
*
* @return true if so. False if not or not implemented.
*/
public abstract boolean isStatisticsEnabled();
/**
* If all builds should be added to statistics logging, not just unsuccessful builds.
* Only relevant if {@link #isStatisticsEnabled()} is true.
*
* @return true if set, false otherwise or if not implemented
*/
public abstract boolean isSuccessfulLoggingEnabled();
/**
* Saves the Statistics.
* @param stat the Statistics.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
*/
public abstract void saveStatistics(Statistics stat) throws Exception;
/**
* Gets Statistics data. This method needs to be implemented in subclass for graph support.
* @param filter the filter to use when fetching data
* @param limit number of statistics items to fetch, set to nonpositive value to fetch all
* @return the list of statistics.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
*/
public List<Statistics> getStatistics(GraphFilterBuilder filter, int limit) throws Exception {
return Collections.<Statistics>emptyList();
}
/**
* Gets a list of {@link ObjectCountPair} where each pair contains a unique {@link FailureCause} as key
* and the number of times that failure cause was triggered as count.
* The list is sorted by counts, meaning that the FailureCause that has been triggered the most comes first.
* This method needs to be implemented in subclass for graph support.
*
* @param filter the filter to use when fetching data
* @return list of ObjectCountPairs.
*/
public List<ObjectCountPair<FailureCause>> getNbrOfFailureCauses(GraphFilterBuilder filter) {
return Collections.<ObjectCountPair<FailureCause>>emptyList();
}
/**
* Gets the quota of unknown failure causes mapped by time periods.
* This method needs to be implemented in subclass for graph support.
* @param intervalSize the interval sizes in which the data is grouped.
* Should be set to Calendar.MONTH, Calendar.DATE or Calendar.HOUR_OF_DAY.
* @param filter The filter to use when fetching the data
* @return failure cause quotas
*/
public Map<TimePeriod, Double> getUnknownFailureCauseQuotaPerTime(int intervalSize, GraphFilterBuilder filter) {
return Collections.<TimePeriod, Double>emptyMap();
}
/**
* Gets a list of {@link ObjectCountPair}s where each pair contains a unique {@link FailureCause}-name as key
* and the number of times that failure cause was triggered as count.
* This list is sorted by counts, meaning that the FailureCause that has been triggered the most comes first.
* This method needs to be implemented in subclass for graph support.
*
* @param filter The filter to use when fetching the data
* @return List of ObjectCountPairs that consist of a name and count
*/
public List<ObjectCountPair<String>> getFailureCauseNames(GraphFilterBuilder filter) {
return Collections.<ObjectCountPair<String>>emptyList();
}
/**
* Counts how many statistics posts there are without FailureCause (null) for a given filter.
* This method needs to be implemented in subclass for graph support.
* @param filter the filter to use when fetching data
* @return number of statistics posts without FailureCause
*/
public long getNbrOfNullFailureCauses(GraphFilterBuilder filter) {
return DEFAULT_NBR_OF_NULL_FAILURE_CAUSES;
}
/**
* Gets a list of {@link ObjectCountPair} where each pair contains a unique failure category string as key
* and the number of times that the failure cause category was triggered as count.
* The list is sorted by counts, meaning that the Category that has been triggered the most comes first.
* This method needs to be implemented in subclass for graph support.
*
* @param filter the filter to use when fetching data
* @param limit the number of categories to fetch, set to nonpositive value to fetch all
* @return list of ObjectCountPairs
*/
public List<ObjectCountPair<String>> getNbrOfFailureCategoriesPerName(GraphFilterBuilder filter, int limit) {
return Collections.<ObjectCountPair<String>>emptyList();
}
/**
* Gets a map where a lists of failure causes are mapped
* by the build number for which they were triggered.
* This method needs to be implemented in subclass for graph support.
*
* @param filter the filter to use when fetching data
* @return map of failure causes
*/
public Map<Integer, List<FailureCause>> getFailureCausesPerBuild(GraphFilterBuilder filter) {
return Collections.<Integer, List<FailureCause>>emptyMap();
}
/**
* Fetches failure causes grouped in time intervals. The returned list does not have to be sorted,
* and one list element is created for each FailureCause for each time interval there exist data.
* This method needs to be implemented in subclass for graph support.
*
* @param intervalSize the interval sizes in which the data is grouped.
* Should be set to Calendar.MONTH, Calendar.DATE or Calendar.HOUR_OF_DAY.
* @param filter the filter to use when fetching data
* @param byCategories set to true in order to group failure causes by their categories
* @return list of FailureCauseTimeIntervals
*/
public List<FailureCauseTimeInterval> getFailureCausesPerTime(int intervalSize, GraphFilterBuilder filter,
boolean byCategories) {
return Collections.<FailureCauseTimeInterval>emptyList();
}
/**
* Gets a list of {@link ObjectCountPair} where each pair contains a unique FailureCause id as key
* and a belonging count value for how many times that FailureCause was triggered.
* This method needs to be implemented in subclass for graph support.
*
* @param filter the filter to use when fetching data
* @param limit the number of items to fetch, set to nonpositive value to fetch all
* @return list of ObjectCountPairs
*/
public List<ObjectCountPair<String>> getNbrOfFailureCausesPerId(GraphFilterBuilder filter, int limit) {
return Collections.<ObjectCountPair<String>>emptyList();
}
/**
* Find the time at which the latest Failure occurred which matches the provided FailureCause.
* This method needs to be implemented in subclass if last seen-functionality is to be supported.
*
* @param id the FailureCause to match.
* @return the time at which the latest Failure occurred.
*/
public Date getLatestFailureForCause(String id) {
return null;
}
/**
* Set the time at which FailureCauses identified by ids last occurred.
* This method needs to be implemented in subclass if last seen-functionality is to be supported.
*
* @param ids the ids of FailureCauses which occurred.
* @param seen the time at which the FailureCauses occurred.
*/
public void updateLastSeen(List<String> ids, Date seen) {
return;
}
/**
* Find out when the FailureCause identified by id was first created.
* This method needs to be implemented in subclass if last modified-functionality is to work correctly
* when upgrading from a version without this functionality.
*
* @param id the id of the FailureCause which info to retrieve.
* @return the Date at which the cause was created, or unix epoch if unknown.
*/
public Date getCreationDateForCause(String id) {
return new Date(0);
}
/**
* Removes the build failure cause of particular build.
* @param build the build.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
* @deprecated use {@link #removeBuildfailurecause(hudson.model.Run)}
*/
@Deprecated
public void removeBuildfailurecause(AbstractBuild build) throws Exception {
if (Util.isOverridden(KnowledgeBase.class, getClass(), "removeBuildfailurecause", Run.class)) {
removeBuildfailurecause((Run)build);
}
}
/**
* Removes the build failure cause of particular build.
* @param build the build.
* @throws Exception if something in the KnowledgeBase handling goes wrong.
*/
public void removeBuildfailurecause(Run build) throws Exception {
if (Util.isOverridden(KnowledgeBase.class, getClass(), "removeBuildfailurecause", AbstractBuild.class)) {
removeBuildfailurecause((AbstractBuild)build);
}
}
/**
* Descriptor for {@link KnowledgeBase}s.
*/
public abstract static class KnowledgeBaseDescriptor extends Descriptor<KnowledgeBase> {
/**
* All registered {@link KnowledgeBaseDescriptor}s.
*
* @return the extension list.
*/
public static ExtensionList<KnowledgeBaseDescriptor> all() {
return Jenkins.getInstance().getExtensionList(KnowledgeBaseDescriptor.class);
}
}
}