/* * 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.domains; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Util; import java.io.ObjectStreamException; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.kohsuke.stapler.DataBoundConstructor; /** * A domain, within which credentials are common. For example a company may have a single sign-on domain where * a bunch of web applications, source control systems, issue trackers, etc all share the same username/password backing * database. */ public class Domain implements Serializable { /** * Set serialization version. */ private static final long serialVersionUID = 1L; /** * The name of the domain, or {@code null} if the special "global" domain. */ @CheckForNull private final String name; /** * The description of the domain. */ @CheckForNull private final String description; /** * The specifications that define the domain. */ @NonNull private final List<DomainSpecification> specifications; @DataBoundConstructor public Domain(String name, String description, List<DomainSpecification> specifications) { this.name = Util.fixEmptyAndTrim(name); this.description = Util.fixEmptyAndTrim(description); this.specifications = specifications == null ? new ArrayList<DomainSpecification>() : new ArrayList<DomainSpecification>(specifications); } /** * Returns the special "global" domain. * * @return the special "global" domain. */ @NonNull public static Domain global() { return ResourceHolder.GLOBAL; } /** * Resolve on deserialization. * * @return the instance. * @throws ObjectStreamException if something goes wrong. */ private Object readResolve() throws ObjectStreamException { return resolve(); } /** * Resolve the correct domain instance. * * @return the correct domain instance (i.e. replaces the global domain with {@link #global()}. */ @SuppressWarnings("ConstantConditions") public Domain resolve() { if (Util.fixEmptyAndTrim(name) == null && Util.fixEmptyAndTrim(description) == null && (specifications == null || specifications.isEmpty())) { return global(); } return this; } /** * Returns the description of this domain. * * @return the description of this domain. */ @CheckForNull @SuppressWarnings("unused") // by stapler public String getDescription() { return description; } /** * Returns the {@link DomainSpecification}s for this {@link Domain}. * * @return the {@link DomainSpecification}s for this {@link Domain}. */ @NonNull @SuppressWarnings("unused") // by stapler public List<DomainSpecification> getSpecifications() { return Collections.unmodifiableList(specifications); } /** * Returns the name of the domain. * * @return the name of the domain. */ @CheckForNull @SuppressWarnings("unused") // by stapler public String getName() { return name; } /** * Return the store relative URL of this domain. * * @return the store relative URL of this domain. */ @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF", justification = "isGlobal() check implies that domain.getName() is null") public String getUrl() { return isGlobal() ? "domain/_/" : "domain/" + Util.rawEncode(name) + "/"; } /** * Tests if this is the {@link #global()} domain. * * @return {@code true} if and only if this is the {@link #global()} domain. * @since 2.0 */ public boolean isGlobal() { return equals(global()); } /** * Returns {@code true} if and only if the supplied {@link DomainRequirement}s are a match for this {@link Domain}. * * @param requirements the {@link DomainRequirement}s to test. * @return {@code true} if and only if the supplied {@link DomainRequirement}s are a match for this {@link Domain}. */ public boolean test(DomainRequirement... requirements) { return test(Arrays.asList(requirements)); } /** * Returns {@code true} if and only if the supplied {@link DomainRequirement}s are a match for this {@link Domain}. * * @param requirements the {@link DomainRequirement}s to test. * @return {@code true} if and only if the supplied {@link DomainRequirement}s are a match for this {@link Domain}. */ public boolean test(@NonNull List<DomainRequirement> requirements) { for (DomainRequirement scope : requirements) { if (scope == null) { continue; } for (DomainSpecification matcher : specifications) { DomainSpecification.Result result = matcher.test(scope); if (result.isDefinitive()) { if (result.isMatch()) { // we have matched this scope => continue with next scope break; } else { // we have a non-test => done return false; } } // continue as nothing is definitive } } // must be a test return true; } /** * {@inheritDoc} */ @Override public int hashCode() { return name != null ? name.hashCode() : 0; } /** * {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Domain domain = (Domain) o; if (name != null ? !name.equals(domain.name) : domain.name != null) { return false; } return true; } /** * Lazy singleton thread-safe initialization. */ private static final class ResourceHolder { private static final Domain GLOBAL = new Domain(null, null, Collections.<DomainSpecification>emptyList()); } }