View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2016 ForgeRock AS.
15   */
16  
17  package org.forgerock.api.models;
18  
19  import static org.forgerock.api.util.ValidationUtil.*;
20  
21  import java.util.HashMap;
22  import java.util.Map;
23  import java.util.Objects;
24  import java.util.Set;
25  
26  import com.fasterxml.jackson.annotation.JsonAnySetter;
27  import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
28  import org.forgerock.api.util.PathUtil;
29  import org.forgerock.http.routing.Version;
30  import org.forgerock.util.Reject;
31  
32  import com.fasterxml.jackson.annotation.JsonIgnore;
33  import com.fasterxml.jackson.annotation.JsonValue;
34  
35  /**
36   * Class that represents the Paths type in API descriptor.
37   */
38  @JsonDeserialize(builder = Paths.Builder.class)
39  public final class Paths {
40  
41      private final Map<String, VersionedPath> paths;
42  
43      private Paths(Builder builder) {
44          this.paths = builder.paths;
45      }
46  
47      /**
48       * Gets a {@code Map} of path-names to Paths. This method is currently only used for JSON serialization.
49       *
50       * @return {@code Map} of path-names to Paths.
51       */
52      @JsonValue
53      protected Map<String, VersionedPath> getPaths() {
54          return paths;
55      }
56  
57      /**
58       * Gets the Path for a given Path-name.
59       *
60       * @param name Path name
61       * @return Path or {@code null} if does-not-exist.
62       */
63      @JsonIgnore
64      public VersionedPath get(String name) {
65          return paths.get(name);
66      }
67  
68      /**
69       * Returns all Path names.
70       *
71       * @return All Path names.
72       */
73      @JsonIgnore
74      public Set<String> getNames() {
75          return paths.keySet();
76      }
77  
78      /**
79       * Create a new Builder for Paths.
80       *
81       * @return Builder
82       */
83      public static Builder paths() {
84          return new Builder();
85      }
86  
87      @Override
88      public boolean equals(Object o) {
89          if (this == o) {
90              return true;
91          }
92          if (o == null || getClass() != o.getClass()) {
93              return false;
94          }
95          Paths paths1 = (Paths) o;
96          return Objects.equals(paths, paths1.paths);
97      }
98  
99      @Override
100     public int hashCode() {
101         return Objects.hash(paths);
102     }
103 
104     /**
105      * Builder to help construct the Paths.
106      */
107     public static final class Builder {
108 
109         private final Map<String, VersionedPath> paths = new HashMap<>();
110 
111         /**
112          * Private default constructor.
113          */
114         private Builder() {
115         }
116 
117         /**
118          * Adds a Path.
119          *
120          * @param path Path string
121          * @param versionedPath Versioned path
122          * @return Builder
123          */
124         @JsonAnySetter
125         public Builder put(String path, VersionedPath versionedPath) {
126             if (path == null || containsWhitespace(path)) {
127                 throw new IllegalArgumentException("path required and may not contain whitespace");
128             }
129             if (!path.isEmpty()) {
130                 // paths must start with a slash (OpenAPI spec) and not end with one
131                 path = PathUtil.buildPath(path);
132             }
133             if (paths.containsKey(path)) {
134                 throw new IllegalStateException("path not unique");
135             }
136             paths.put(path, Reject.checkNotNull(versionedPath));
137             return this;
138         }
139 
140         /**
141          * Merge the path definition into the existing path definitions. If there is already a {@code VersionedPath}
142          * at this path, then the versions will be added together.
143          *
144          * @param path Path string
145          * @param versionedPath Versioned path
146          * @return Builder.
147          */
148         public Builder merge(String path, VersionedPath versionedPath) {
149             if (path == null || containsWhitespace(path)) {
150                 throw new IllegalArgumentException("path required and may not contain whitespace");
151             }
152             if (!path.isEmpty()) {
153                 // paths must start with a slash (OpenAPI spec) and not end with one
154                 path = PathUtil.buildPath(path);
155             }
156             if (!paths.containsKey(path)) {
157                 put(path, Reject.checkNotNull(versionedPath));
158             } else {
159                 VersionedPath existing = paths.get(path);
160                 for (Version v : versionedPath.getVersions()) {
161                     existing.addVersion(v, versionedPath.get(v));
162                 }
163             }
164             return this;
165         }
166 
167         /**
168          * Builds the Paths instance.
169          *
170          * @return Paths instance
171          */
172         public Paths build() {
173             return new Paths(this);
174         }
175     }
176 
177 }