Java tutorial
/* * 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 com.cloudbees.plugins.credentials.common; import com.cloudbees.plugins.credentials.CredentialsMatcher; import com.cloudbees.plugins.credentials.CredentialsMatchers; import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.domains.DomainRequirement; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import hudson.model.Descriptor; import hudson.model.Item; import hudson.model.ItemGroup; import hudson.model.Job; import hudson.util.ListBoxModel; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import jenkins.model.Jenkins; import org.acegisecurity.Authentication; import org.apache.commons.lang.StringUtils; /** * {@link ListBoxModel} with support for credentials. * <p> * This class is convenient for providing the {@code config.groovy} or {@code config.jelly} fragment for a collection * of objects of some {@link IdCredentials} subtype. * </p><p> * If you want to let the user configure a credentials object, do the following: * </p><p> * First, create a field that stores the credentials ID and defines a corresponding parameter in the constructor: * </p> * <pre> * private String credentialsId; * * @DataBoundConstructor * public MyModel( .... , String credentialsId) { * this.credentialsId = credentialsId; * ... * } * public String getCredentialsId() {return credentialsId;} * </pre> * <p> * Your <tt>config.groovy</tt> should have the following entry to render a drop-down list box: * </p> * <pre> * f.entry(title:_("Credentials"), field:"credentialsId") { * f.select() * } * </pre> * <p> * Finally, your {@link Descriptor} implementation should have the <tt>doFillCredentialsIdItems</tt> method, which * lists up the credentials available in this context: * </p> * <pre> * public ListBoxModel doFillCredentialsIdItems(@QueryParam String value) { * if (!Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER)) { // or whatever permission is appropriate for * this page * // Important! Otherwise you expose credentials metadata to random web requests. * return new StandardUsernameListBoxModel().includeCurrentValue(value); * } * return new StandardUsernameListBoxModel() * .includeEmptySelection() * .include(StandardUsernameCredentials.class,...)) * .includeCurrentValue(value); * } * </pre> * <p> * Exactly which overloaded version of the {@link #include(Item, Class)} depends on * the context in which your model operates. Here are a few common examples: * </p> * <dl> * <dt>System-level settings * <dd> * If your model is a singleton in the whole Jenkins instance, things that belong to the root {@link Jenkins} * (such as slaves), or do not have any ancestors serving as the context, then use {@link Jenkins#getInstance} as the * context. * <dt>Job-level settings * <dd> * If your model is a configuration fragment added to a {@link Item} (such as its major subtype {@link Job}), * then use that {@link Item} as the context. * For example: * <pre> * public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item context, @QueryParameter String source) { * if (context == null || !context.hasPermission(Item.CONFIGURE)) { * return new StandardUsernameListBoxModel().includeCurrentValue(value); * } * return new StandardUsernameListBoxModel() * .includeEmptySelection() * .includeAs(Tasks.getAuthenticationOf(context), context, StandardUsernameCredentials.class, * URIRequirementBuilder.fromUri(source).build()) * .includeCurrentValue(value); * } * </pre> * </dl> * * @since 1.6 */ public abstract class AbstractIdCredentialsListBoxModel<T extends AbstractIdCredentialsListBoxModel<T, C>, C extends IdCredentials> extends ListBoxModel { /** * Generate a description of the supplied credential. * * @param c the credential. * @return the description. */ @NonNull protected abstract String describe(@NonNull C c); /** * Adds a single credential. * * @param u the credential to add. * @return {@code this} for method chaining. */ @NonNull public AbstractIdCredentialsListBoxModel<T, C> with(@CheckForNull C u) { if (u != null) { add(describe(u), u.getId()); } return this; } /** * Adds an "empty" credential to signify selection of no credential. * * @return {@code this} for method chaining. * @deprecated use {@link #includeEmptyValue()} */ @Deprecated @NonNull public AbstractIdCredentialsListBoxModel<T, C> withEmptySelection() { return includeEmptyValue(); } /** * Adds an "empty" credential to signify selection of no credential. * * @return {@code this} for method chaining. * @since 2.1.0 */ @NonNull public AbstractIdCredentialsListBoxModel<T, C> includeEmptyValue() { for (Option a : this) { if (StringUtils.equals("", a.value)) { return this; } } add(0, new Option(Messages.AbstractIdCredentialsListBoxModel_EmptySelection(), "")); return this; } /** * Adds supplied credentials to the model. * * @param credentials the credentials. * @return {@code this} for method chaining. * @deprecated prefer using the {@link #include(Item, Class)} or {@link #includeAs(Authentication, Item, Class)} * methods to build the list box contents in order to allow credentials providers to not have to instantiate * a full credential instance where those credential providers store the secrets external from Jenkins. */ @Deprecated @NonNull public AbstractIdCredentialsListBoxModel<T, C> withAll(@NonNull C... credentials) { return withMatching(CredentialsMatchers.always(), Arrays.asList(credentials)); } /** * Adds supplied credentials to the model. * * @param credentials the credentials. * @return {@code this} for method chaining. * @deprecated prefer using the {@link #include(Item, Class)} or {@link #includeAs(Authentication, Item, Class)} * methods to build the list box contents in order to allow credentials providers to not have to instantiate * a full credential instance where those credential providers store the secrets external from Jenkins. */ @Deprecated @NonNull public AbstractIdCredentialsListBoxModel<T, C> withAll(@NonNull Iterable<? extends C> credentials) { return withMatching(CredentialsMatchers.always(), credentials.iterator()); } /** * Adds supplied credentials to the model. * * @param credentials the credentials. * @return {@code this} for method chaining. * @deprecated prefer using the {@link #include(Item, Class)} or {@link #includeAs(Authentication, Item, Class)} * methods to build the list box contents in order to allow credentials providers to not have to instantiate * a full credential instance where those credential providers store the secrets external from Jenkins. */ @Deprecated @NonNull public AbstractIdCredentialsListBoxModel<T, C> withAll(@NonNull Iterator<? extends C> credentials) { return withMatching(CredentialsMatchers.always(), credentials); } /** * Adds the matching subset of suppled credentials to the model. * * @param matcher the matcher. * @param credentials the superset of credentials. * @return {@code this} for method chaining. * @deprecated prefer using the {@link #includeMatching(Item, Class, List, CredentialsMatcher)} * or {@link #includeMatchingAs(Authentication, Item, Class, List, CredentialsMatcher)} * methods to build the list box contents in order to allow credentials providers to not have to instantiate * a full credential instance where those credential providers store the secrets external from Jenkins. */ @Deprecated @NonNull public AbstractIdCredentialsListBoxModel<T, C> withMatching(@NonNull CredentialsMatcher matcher, @NonNull C... credentials) { return withMatching(matcher, Arrays.asList(credentials)); } /** * Adds the matching subset of suppled credentials to the model. * * @param matcher the matcher. * @param credentials the superset of credentials. * @return {@code this} for method chaining. * @deprecated prefer using the {@link #includeMatching(Item, Class, List, CredentialsMatcher)} * or {@link #includeMatchingAs(Authentication, Item, Class, List, CredentialsMatcher)} * methods to build the list box contents in order to allow credentials providers to not have to instantiate * a full credential instance where those credential providers store the secrets external from Jenkins. */ @Deprecated @NonNull public AbstractIdCredentialsListBoxModel<T, C> withMatching(@NonNull CredentialsMatcher matcher, @NonNull Iterable<? extends C> credentials) { return withMatching(matcher, credentials.iterator()); } /** * Adds the matching subset of suppled credentials to the model. * * @param matcher the matcher. * @param credentials the superset of credentials. * @return {@code this} for method chaining. * @deprecated prefer using the {@link #includeMatching(Item, Class, List, CredentialsMatcher)} * or {@link #includeMatchingAs(Authentication, Item, Class, List, CredentialsMatcher)} * methods to build the list box contents in order to allow credentials providers to not have to instantiate * a full credential instance where those credential providers store the secrets external from Jenkins. */ @Deprecated @NonNull public AbstractIdCredentialsListBoxModel<T, C> withMatching(@NonNull CredentialsMatcher matcher, @NonNull Iterator<? extends C> credentials) { while (credentials.hasNext()) { C c = credentials.next(); if (matcher.matches(c)) { with(c); } } return this; } /** * Adds the ids of the specified credential type that are available to the specified context as the current * authentication. * * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, Item, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> include(@Nullable Item context, @NonNull Class<? extends C> type) { return include(context, type, Collections.<DomainRequirement>emptyList()); } /** * Adds the ids of the specified credential type that are available to the specified context as the current * authentication. * * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, ItemGroup, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> include(@NonNull ItemGroup context, @NonNull Class<? extends C> type) { return include(context, type, Collections.<DomainRequirement>emptyList()); } /** * Adds the ids of the specified credential type that are available to the specified context as the specified * authentication. * * @param authentication the authentication to search with * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, Item, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> includeAs(@NonNull Authentication authentication, @Nullable Item context, @NonNull Class<? extends C> type) { return includeAs(authentication, context, type, Collections.<DomainRequirement>emptyList()); } /** * Adds the ids of the specified credential type that are available to the specified context as the specified * authentication. * * @param authentication the authentication to search with * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, ItemGroup, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> includeAs(@NonNull Authentication authentication, @NonNull ItemGroup context, @NonNull Class<? extends C> type) { return includeAs(authentication, context, type, Collections.<DomainRequirement>emptyList()); } /** * Adds the ids of the specified credential type that are available to the specified context as the current * authentication with the specified domain requirements. * * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @param domainRequirements the domain requirements. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, Item, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> include(@Nullable Item context, @NonNull Class<? extends C> type, @NonNull List<DomainRequirement> domainRequirements) { return includeMatching(context, type, domainRequirements, CredentialsMatchers.always()); } /** * Adds the ids of the specified credential type that are available to the specified context as the current * authentication with the specified domain requirements. * * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @param domainRequirements the domain requirements. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, ItemGroup, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> include(@NonNull ItemGroup context, @NonNull Class<? extends C> type, @NonNull List<DomainRequirement> domainRequirements) { return includeMatching(context, type, domainRequirements, CredentialsMatchers.always()); } /** * Adds the ids of the specified credential type that are available to the specified context as the specified * authentication with the specified domain requirements. * * @param authentication the authentication to search with * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @param domainRequirements the domain requirements. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, Item, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> includeAs(@NonNull Authentication authentication, @Nullable Item context, @NonNull Class<? extends C> type, @NonNull List<DomainRequirement> domainRequirements) { return includeMatchingAs(authentication, context, type, domainRequirements, CredentialsMatchers.always()); } /** * Adds the ids of the specified credential type that are available to the specified context as the specified * authentication with the specified domain requirements. * * @param authentication the authentication to search with * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @param domainRequirements the domain requirements. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, ItemGroup, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> includeAs(@NonNull Authentication authentication, @NonNull ItemGroup context, @NonNull Class<? extends C> type, @NonNull List<DomainRequirement> domainRequirements) { return includeMatchingAs(authentication, context, type, domainRequirements, CredentialsMatchers.always()); } /** * Adds the ids of the specified credential type that are available to the specified context as the current * authentication with the specified domain requirements and match the specified filter. * * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @param domainRequirements the domain requirements. * @param matcher the filter to apply to the credentials. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, Item, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> includeMatching(@Nullable Item context, @NonNull Class<? extends C> type, @NonNull List<DomainRequirement> domainRequirements, @NonNull CredentialsMatcher matcher) { return includeMatchingAs(Jenkins.getAuthentication(), context, type, domainRequirements, matcher); } /** * Adds the ids of the specified credential type that are available to the specified context as the current * authentication with the specified domain requirements and match the specified filter. * * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @param domainRequirements the domain requirements. * @param matcher the filter to apply to the credentials. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, ItemGroup, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> includeMatching(@NonNull ItemGroup context, @NonNull Class<? extends C> type, @NonNull List<DomainRequirement> domainRequirements, @NonNull CredentialsMatcher matcher) { return includeMatchingAs(Jenkins.getAuthentication(), context, type, domainRequirements, matcher); } /** * Adds the ids of the specified credential type that are available to the specified context as the specified * authentication with the specified domain requirements and match the specified filter. * * @param authentication the authentication to search with * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @param domainRequirements the domain requirements. * @param matcher the filter to apply to the credentials. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, Item, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> includeMatchingAs(@NonNull Authentication authentication, @Nullable Item context, @NonNull Class<? extends C> type, @NonNull List<DomainRequirement> domainRequirements, @NonNull CredentialsMatcher matcher) { addMissing(CredentialsProvider.listCredentials(type, context, authentication, domainRequirements, matcher)); return this; } /** * Adds the ids of the specified credential type that are available to the specified context as the specified * authentication with the specified domain requirements and match the specified filter. * * @param authentication the authentication to search with * @param context the context to add credentials from. * @param type the base class of the credentials to add. * @param domainRequirements the domain requirements. * @param matcher the filter to apply to the credentials. * @return {@code this} for method chaining. * @see CredentialsProvider#listCredentials(Class, ItemGroup, Authentication, List, CredentialsMatcher) * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> includeMatchingAs(@NonNull Authentication authentication, @NonNull ItemGroup context, @NonNull Class<? extends C> type, @NonNull List<DomainRequirement> domainRequirements, @NonNull CredentialsMatcher matcher) { addMissing(CredentialsProvider.listCredentials(type, context, authentication, domainRequirements, matcher)); return this; } /** * Ensures that the current value is present so that the form can be idempotently saved in those cases where the * user saving the form cannot view the current credential * * @param value the current value. * @return {@code this} for method chaining. * @since 2.1.0 */ public AbstractIdCredentialsListBoxModel<T, C> includeCurrentValue(@NonNull String value) { if (StringUtils.isEmpty(value)) { return includeEmptyValue(); } for (Option a : this) { if (StringUtils.equals(value, a.value)) { return this; } } // the current should be the first (unless the first is the empty selection int index = isEmpty() ? 0 : "".equals(get(0).value) ? 1 : 0; add(index, new Option(Messages.AbstractIdCredentialsListBoxModel_CurrentSelection(), value)); return this; } /** * Appends all of the missing elements from the specified collection to the end of * this list, in the order that they are returned by the * specified collection's Iterator. The behavior of this operation is * undefined if the specified collection is modified while the operation * is in progress. (This implies that the behavior of this call is * undefined if the specified collection is this list, and this * list is nonempty.) * * @param c collection containing elements to be added to this list * @return <tt>true</tt> if this list changed as a result of the call * @since 2.1.0 */ public boolean addMissing(@NonNull Collection<? extends Option> c) { Set<String> existing = new HashSet<String>(); for (Option o : this) { existing.add(o.value); } boolean changed = false; for (Option o : c) { if (!existing.contains(o.value)) { add(o); changed = existing.add(o.value) || changed; } } return changed; } }