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.json.resource;
18  
19  import static org.forgerock.api.models.ApiDescription.*;
20  import static org.forgerock.api.models.Paths.*;
21  import static org.forgerock.api.models.VersionedPath.*;
22  import static org.forgerock.util.Reject.*;
23  
24  import org.forgerock.api.models.ApiDescription;
25  import org.forgerock.api.models.Resource;
26  import org.wrensecurity.guava.common.base.Optional;
27  import org.forgerock.http.ApiProducer;
28  import org.forgerock.services.context.Context;
29  import org.forgerock.services.descriptor.Describable;
30  
31  /**
32   * A resource handler that implements describable for a possibly annotated type. This class should be used by internal
33   * CREST {@link RequestHandler}s that are wrapping a type that uses (or may use) annotations to describe its API - for
34   * example, the Interface handlers and Annotated handlers that the {@link Resources} class uses.
35   * <p>
36   * Note that this class does not support the API changing once it has been defined.
37   * </p>
38   */
39  final class DescribableResourceHandler implements Describable<ApiDescription, Request> {
40  
41      private final ApiDescription definitionDescriptions;
42      private ApiDescription api;
43      private Optional<Resource> resource;
44  
45      DescribableResourceHandler() {
46          // This ApiDescription can have a dummy ID and version because we are never going to expose it - it is used to
47          // collect top-level definitions that are referenced in the resource. Any referenced definitions and errors
48          // are added to the ApiDescription that has a proper ID and version (once they are known) in the api method
49          // below.
50          this.definitionDescriptions = apiDescription().id("fake:id").version("0.0").build();
51      }
52  
53      ApiDescription getDefinitionDescriptions() {
54          return definitionDescriptions;
55      }
56  
57      void describes(Resource resource) {
58          rejectStateIfTrue(this.resource != null, "Already described API");
59          this.resource = Optional.fromNullable(resource);
60      }
61  
62      @Override
63      public final ApiDescription api(ApiProducer<ApiDescription> producer) {
64          rejectStateIfTrue(resource == null, "Not yet described API");
65          if (api == null && resource.isPresent()) {
66              api = producer.addApiInfo(ApiDescription.apiDescription().id("fake:id").version("0.0")
67                      .definitions(definitionDescriptions.getDefinitions())
68                      .errors(definitionDescriptions.getErrors())
69                      .services(definitionDescriptions.getServices())
70                      .paths(paths().put("", versionedPath().put(UNVERSIONED, resource.get()).build()).build())
71                      .build());
72          }
73          return api;
74      }
75  
76      @Override
77      public ApiDescription handleApiRequest(Context context, Request request) {
78          rejectStateIfTrue(api == null, "Not ready for API Descriptor requests");
79          return api;
80      }
81  
82      @Override
83      public void addDescriptorListener(Describable.Listener listener) {
84          // No-op: change to API not supported.
85      }
86  
87      @Override
88      public void removeDescriptorListener(Describable.Listener listener) {
89          // No-op: change to API not supported.
90      }
91  }