/*
* The MIT License
*
* Copyright (c) 2011-2013, CloudBees, Inc., Stephen Connolly.
*
* 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 jenkins.scm.api;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.ExtensionList;
import hudson.model.Descriptor;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import jenkins.scm.impl.UncategorizedSCMHeadCategory;
import net.jcip.annotations.GuardedBy;
import org.jenkins.ui.icon.IconSpec;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* A {@link Descriptor} for {@link SCMSource}s.
*
* @author Stephen Connolly
*/
public abstract class SCMSourceDescriptor extends Descriptor<SCMSource> implements IconSpec {
/**
* The set of {@link SCMHeadCategory} singletons for this type of {@link SCMSource}
*
* @see #getCategories()
* @since 2.0
*/
@GuardedBy("this")
protected transient Set<SCMHeadCategory> categories;
/**
* Return or generate the ID for a source instance.
*
* @param source the source or {@code null} if a new source.
* @return the ID of the supplied source or a newly generated ID to use for a new source instance.
*/
@NonNull
@SuppressWarnings("unused") // use by stapler as well as elsewhere
public String getId(@CheckForNull SCMSource source) {
return source == null ? UUID.randomUUID().toString() : source.getId();
}
/**
* Returns {@code true} if this source type is applicable to the given owner.
*
* @param owner the type of owner.
* @return true to allow user to select and configure this source.
*/
public boolean isApplicable(java.lang.Class<? extends SCMSourceOwner> owner) {
return true;
}
/**
* Returns {@code true} if the source type is one that the user is permitted to configure. Where a source is
* used to wrap or decorate another source it may make sense to return {@code false}.
*
* @return {@code true} if the source type is one that the user is permitted to configure via the UI.
*/
@Restricted(NoExternalUse.class)
public boolean isUserInstantiable() {
return true;
}
/**
* Returns the list of descriptors that are appropriate for a specified owner and {@link #isUserInstantiable()}.
*
* @param owner the owner.
* @return the list of descriptors
*/
@NonNull
@SuppressWarnings("unused") // used by stapler
public static List<SCMSourceDescriptor> forOwner(@CheckForNull SCMSourceOwner owner) {
return forOwner(owner == null ? SCMSourceOwner.class : owner.getClass(), true);
}
/**
* Returns the list of descriptors that are appropriate for a specified owner with the additional filter by
* {@link #isUserInstantiable()}.
*
* @param owner the owner.
* @param onlyUserInstantiable {@code true} if only those descriptors that are {@link #isUserInstantiable()}.
* @return the list of descriptors
*/
@NonNull
@SuppressWarnings("unused") // used by stapler
public static List<SCMSourceDescriptor> forOwner(@CheckForNull SCMSourceOwner owner,
boolean onlyUserInstantiable) {
return forOwner(owner == null ? SCMSourceOwner.class : owner.getClass(), onlyUserInstantiable);
}
/**
* Returns the list of descriptors that are appropriate for a specified type of owner and
* {@link #isUserInstantiable()}.
*
* @param clazz the type of owner.
* @return the list of descriptors
*/
@NonNull
@SuppressWarnings("unused") // used by stapler
public static List<SCMSourceDescriptor> forOwner(Class<? extends SCMSourceOwner> clazz) {
return forOwner(clazz, true);
}
/**
* Returns the list of descriptors that are appropriate for a specified type of owner with the additional
* filter by
* {@link #isUserInstantiable()}.
*
* @param clazz the type of owner.
* @param onlyUserInstantiable {@code true} if only those descriptors that are {@link #isUserInstantiable()}.
* @return the list of descriptors
*/
@NonNull
@SuppressWarnings("unused") // used by stapler
public static List<SCMSourceDescriptor> forOwner(Class<? extends SCMSourceOwner> clazz,
boolean onlyUserInstantiable) {
List<SCMSourceDescriptor> result = new ArrayList<SCMSourceDescriptor>();
for (SCMSourceDescriptor d : ExtensionList.lookup(SCMSourceDescriptor.class)) {
SCMSourceDescriptor descriptor = (SCMSourceDescriptor) d;
if (descriptor.isApplicable(clazz) && (!onlyUserInstantiable || descriptor.isUserInstantiable())) {
result.add(descriptor);
}
}
return result;
}
/**
* Used to categorize this kind of {@link SCMSource}
* @return The Icon class specification e.g. 'icon-notepad'.
*/
@Override
public String getIconClassName() {
return null;
}
/**
* Get the term used in the UI to represent this kind of {@link SCMSource}. Must start with a capital letter.
*
* @return the term or {@code null} to fall back to the calling context's default.
* @since 2.0
*/
@CheckForNull
public String getPronoun() {
return null;
}
/**
* Returns the set of {@link SCMHeadCategory} that this {@link SCMSource} supports. There will always be
* exactly one {@link SCMCategory#isUncategorized()} instance in the returned set.
*
* @return the set of {@link SCMHeadCategory} that this {@link SCMSource} supports.
* @since 2.0
*/
@NonNull
public synchronized final Set<SCMHeadCategory> getCategories() {
if (categories == null) {
Set<SCMHeadCategory> categories = new LinkedHashSet<SCMHeadCategory>();
boolean haveDefault = false;
for (SCMHeadCategory c : createCategories()) {
if (c.isUncategorized()) {
if (!haveDefault) {
categories.add(c);
haveDefault = true;
}
} else {
categories.add(c);
}
}
if (!haveDefault) {
categories.add(UncategorizedSCMHeadCategory.DEFAULT);
}
this.categories = Collections.unmodifiableSet(categories);
}
return categories;
}
/**
* Creates the singleton {@link SCMHeadCategory} instances that this type of {@link SCMSource} is capable of
* producing.
*
* @return the singleton {@link SCMHeadCategory} instances for this type of {@link SCMSource}
* @see #getCategories()
* @since 2.0
*/
@NonNull
@GuardedBy("this")
protected SCMHeadCategory[] createCategories() {
return new SCMHeadCategory[]{UncategorizedSCMHeadCategory.DEFAULT};
}
}