DescribableResourceHandler.java
/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2016 ForgeRock AS.
*/
package org.forgerock.json.resource;
import static org.forgerock.api.models.ApiDescription.*;
import static org.forgerock.api.models.Paths.*;
import static org.forgerock.api.models.VersionedPath.*;
import static org.forgerock.util.Reject.*;
import org.forgerock.api.models.ApiDescription;
import org.forgerock.api.models.Resource;
import org.wrensecurity.guava.common.base.Optional;
import org.forgerock.http.ApiProducer;
import org.forgerock.services.context.Context;
import org.forgerock.services.descriptor.Describable;
/**
* A resource handler that implements describable for a possibly annotated type. This class should be used by internal
* CREST {@link RequestHandler}s that are wrapping a type that uses (or may use) annotations to describe its API - for
* example, the Interface handlers and Annotated handlers that the {@link Resources} class uses.
* <p>
* Note that this class does not support the API changing once it has been defined.
* </p>
*/
final class DescribableResourceHandler implements Describable<ApiDescription, Request> {
private final ApiDescription definitionDescriptions;
private ApiDescription api;
private Optional<Resource> resource;
DescribableResourceHandler() {
// This ApiDescription can have a dummy ID and version because we are never going to expose it - it is used to
// collect top-level definitions that are referenced in the resource. Any referenced definitions and errors
// are added to the ApiDescription that has a proper ID and version (once they are known) in the api method
// below.
this.definitionDescriptions = apiDescription().id("fake:id").version("0.0").build();
}
ApiDescription getDefinitionDescriptions() {
return definitionDescriptions;
}
void describes(Resource resource) {
rejectStateIfTrue(this.resource != null, "Already described API");
this.resource = Optional.fromNullable(resource);
}
@Override
public final ApiDescription api(ApiProducer<ApiDescription> producer) {
rejectStateIfTrue(resource == null, "Not yet described API");
if (api == null && resource.isPresent()) {
api = producer.addApiInfo(ApiDescription.apiDescription().id("fake:id").version("0.0")
.definitions(definitionDescriptions.getDefinitions())
.errors(definitionDescriptions.getErrors())
.services(definitionDescriptions.getServices())
.paths(paths().put("", versionedPath().put(UNVERSIONED, resource.get()).build()).build())
.build());
}
return api;
}
@Override
public ApiDescription handleApiRequest(Context context, Request request) {
rejectStateIfTrue(api == null, "Not ready for API Descriptor requests");
return api;
}
@Override
public void addDescriptorListener(Describable.Listener listener) {
// No-op: change to API not supported.
}
@Override
public void removeDescriptorListener(Describable.Listener listener) {
// No-op: change to API not supported.
}
}