001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2016 ForgeRock AS. 015 */ 016 017package org.forgerock.api.models; 018 019import static org.forgerock.api.util.ValidationUtil.*; 020 021import java.util.HashMap; 022import java.util.Map; 023import java.util.Objects; 024import java.util.Set; 025 026import com.fasterxml.jackson.annotation.JsonAnySetter; 027import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 028import org.forgerock.api.util.PathUtil; 029import org.forgerock.util.Reject; 030 031import com.fasterxml.jackson.annotation.JsonIgnore; 032import com.fasterxml.jackson.annotation.JsonValue; 033 034/** 035 * Sub-resources of a resource are declared here. 036 */ 037@JsonDeserialize(builder = SubResources.Builder.class) 038public final class SubResources { 039 private final Map<String, Resource> subResources; 040 041 private SubResources(Builder builder) { 042 this.subResources = builder.subResources; 043 } 044 045 /** 046 * Gets a {@code Map} of paths to {@link Resource}s. 047 * 048 * @return The {@code Map}. 049 */ 050 @JsonValue 051 public Map<String, Resource> getSubResources() { 052 return subResources; 053 } 054 055 /** 056 * Gets the {@link Resource} for a given sub-resource name. 057 * 058 * @param name Sub-resource name 059 * @return {@link Resource} or {@code null} if does-not-exist. 060 */ 061 @JsonIgnore 062 public Resource get(String name) { 063 return subResources.get(name); 064 } 065 066 /** 067 * Returns all sub-resource names. 068 * 069 * @return The names. 070 */ 071 @JsonIgnore 072 public Set<String> getNames() { 073 return subResources.keySet(); 074 } 075 076 @Override 077 public boolean equals(Object o) { 078 if (this == o) { 079 return true; 080 } 081 if (o == null || getClass() != o.getClass()) { 082 return false; 083 } 084 SubResources that = (SubResources) o; 085 return Objects.equals(subResources, that.subResources); 086 } 087 088 @Override 089 public int hashCode() { 090 return Objects.hash(subResources); 091 } 092 093 /** 094 * Create a new Builder for sub-resources. 095 * 096 * @return Builder 097 */ 098 public static Builder subresources() { 099 return new Builder(); 100 } 101 102 /** 103 * Builder to help construct the SubResources. 104 */ 105 public static final class Builder { 106 107 private final Map<String, Resource> subResources = new HashMap<>(); 108 109 /** 110 * Private default constructor. 111 */ 112 private Builder() { 113 } 114 115 /** 116 * Adds a sub-resource. 117 * 118 * @param path Sub-resource path 119 * @param resource {@link Resource} 120 * @return Builder 121 */ 122 @JsonAnySetter 123 public Builder put(String path, Resource resource) { 124 if (path == null || containsWhitespace(path)) { 125 throw new IllegalArgumentException("path required and may not contain whitespace"); 126 } 127 if (!path.isEmpty()) { 128 // paths must start with a slash (OpenAPI spec) and not end with one 129 path = PathUtil.buildPath(path); 130 } 131 if (subResources.containsKey(path)) { 132 throw new IllegalStateException("path not unique"); 133 } 134 subResources.put(path, Reject.checkNotNull(resource)); 135 return this; 136 } 137 138 /** 139 * Builds the {@link SubResources} instance. 140 * 141 * @return {@link SubResources} instance 142 */ 143 public SubResources build() { 144 return new SubResources(this); 145 } 146 } 147 148}